<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Weather Display Archives - Digital Urban</title>
	<atom:link href="https://www.digitalurban.org/blog/category/weather-display/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.digitalurban.org/blog/category/weather-display/</link>
	<description>Data, Cities, IoT, Writing, Music and Making Things</description>
	<lastBuildDate>Wed, 06 Aug 2025 08:42:15 +0000</lastBuildDate>
	<language>en-GB</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://www.digitalurban.org/wp-content/uploads/2012/07/Dulogosm-1.png</url>
	<title>Weather Display Archives - Digital Urban</title>
	<link>https://www.digitalurban.org/blog/category/weather-display/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Chasing the Tween: My 25-Year Obsession with Weather Data</title>
		<link>https://www.digitalurban.org/blog/2025/07/25/chasing-the-tween-my-25-year-obsession-with-weather-data/</link>
		
		<dc:creator><![CDATA[Andy]]></dc:creator>
		<pubDate>Fri, 25 Jul 2025 13:04:19 +0000</pubDate>
				<category><![CDATA[Weather]]></category>
		<category><![CDATA[Weather Display]]></category>
		<guid isPermaLink="false">https://www.digitalurban.org/blog/2025/07/25/chasing-the-tween-my-25-year-obsession-with-weather-data/</guid>

					<description><![CDATA[<p>From Adobe Flash through to Vibe Coding and back again to Physical Displays</p>
<p>The post <a href="https://www.digitalurban.org/blog/2025/07/25/chasing-the-tween-my-25-year-obsession-with-weather-data/">Chasing the Tween: My 25-Year Obsession with Weather Data</a> appeared first on <a href="https://www.digitalurban.org">Digital Urban</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h2 class="wp-block-heading">From Adobe Flash through to Vibe Coding and back again to Physical Displays</h2>



<p>For those of us who run a personal weather station (PWS), the obsession isn&#8217;t just about collecting data; it&#8217;s about seeing it and sharing it, and that often means an online data dashboard. At the Connected Environments Lab based within the Centre for Advanced Spatial Analysis, University College London, we have been running weather stations in Central London since the early 2000s, each one uploading and communicating data every 3 seconds &#8211; that&#8217;s approximately 268,918,537 measures of wind speed, air pressure, temperature, and solar intensity, amoungst others, including cloud height and now air quality etc. Getting the data online, however, has never been quite as easy as it should be…</p>



<h3 class="wp-block-heading">The Past: The Golden Age of Tweens and Live Dials</h3>



<p>So, back in the early 2000s, getting a Davis, Oregon Scientific, or La Crosse station online was a rite of passage for anyone interested in environmental data. The challenge wasn&#8217;t just mounting the hardware; it was wrestling with software to display the information. In this era, two names stood out for many hobbyists: Cumulus and Weather Display, and we have used them both extensively over the years.</p>



<p><strong>Weather Display</strong>, the long-standing creation of New Zealand-based developer Brian Hamilton, is a testament to the remarkable longevity of software. First appearing around 1999, it has been continuously developed for over two decades with hundreds of updates, making it a cornerstone of the personal weather station community. Its web component, <strong>Weather Display Live</strong>, became the golden standard for its time. Built entirely on Adobe Flash, it presented a fully featured dashboard of analogue-style gauges and tickers updating in real-time. The wind speed needle would smoothly tween with every gust, the rain gauge would visibly fill, and a ticker tape would scroll with the latest observations, creating a dynamic and immersive view of the weather that was unparalleled in its era. I’ve been chasing that smooth ‘tween’ ever since in dashboards, and indeed, further into this article that tween is still the ultimate draw in real-time data.</p>



<figure class="wp-block-image size-large"><img decoding="async" src="https://www.digitalurban.org/wp-content/uploads/2025/08/6e0f7ac1-9c5c-4146-975e-6040b344b15e_555x414.gif" alt=""/></figure>



<p>By today&#8217;s standards, Weather Display Live perhaps looks cluttered, as design language shifts, indeed we are about to enter the era of ‘glass’ with the latest iOS updates and that will bring about a whole new look to apps and displays. Despite Adobe Flash requiring a browser plugin it allows dashboard that using the then HTML standard would simply not have been possible.</p>



<p>For a brief time Flash burned bright and was the basis of data on a little desktop device known as the Chumby &#8211; the Chumby was a device ahead of its time, providing realtime data updates via a series of rotating dashboards. As such it was the perfect device for displaying weather data, although the technical knowledge at the time, escaped me. Luckly a computer scientist, now <a href="https://profiles.ucl.ac.uk/4441-steven-gray">Professor Steven Gray</a> had recently joined our lab and kindly wrote a custom script to display the data.</p>



<figure class="wp-block-image size-large"><img decoding="async" src="https://www.digitalurban.org/wp-content/uploads/2025/08/d52d9de1-6609-4b62-9a21-48e749430e74_400x294.jpeg" alt=""/></figure>



<p>However, Flash’s days were numbered when Steve Jobs famously called it a ‘bag of hurt’, ushering in a new age of HTML5 and laying the foundations to the web we see today.</p>



<p>Alongside Weather Display was <strong>Cumulus</strong> (now <strong>Cumulus MX</strong>), which carved out a huge following, particularly for Windows users. It was, and is, a robust piece of software for processing PWS data. Its approach to web display was more traditional. It used a system of web templates and tags. You could design a basic HTML page, insert special tags like <code>&lt;#temp&gt;</code>, and Cumulus would periodically process this file, replacing the tags with current data and uploading it to your web server. While it lacked the fluid dynamism of Flash, it was reliable and customisable if you knew your way around HTML and CSS. It represented, arguably the dawn of the template-driven, self-hosted dashboard. Adobe Flash dials were replaced with new plugin free gauges via a system known as Steel Gauges.</p>



<figure class="wp-block-image size-large"><img decoding="async" src="https://www.digitalurban.org/wp-content/uploads/2025/08/47099276-d732-43e5-8f17-0765c9781acc_1146x1363.jpeg" alt=""/></figure>



<p>The Steel Gauges are a much-loved part of the Cumulus software legacy, while not part of the official template that came with the software, they were a hugely popular style that the Cumulus community created and shared, made possible by the software&#8217;s flexible templating system. They are the perfect example of a design philosophy called <strong>skeuomorphism</strong> &#8211; which came and went but is actually one we end this article on with perhaps the best example of a weather dashboard, but more on that later.</p>



<p>Skeuomorphism&#8217;s goal is to make digital items resemble their real-world counterparts. The Steel Gauges aesthetic was heavily influenced by the design trends of the late 2000s and early 2010s, aiming to make a web page look like a physical, high-end piece of hardware. The designs were rich with photorealistic detail: brushed metal or carbon fibre backgrounds, glistening chrome bezels with drop shadows, and precisely rendered needles and tick marks. The goal was to create a sense of tangible reality on the screen.</p>



<p>The implementation was a clever two-part process:</p>



<ol class="wp-block-list">
<li>
<p><strong>The Visuals:</strong> A user would first design the entire dashboard as a single, static background image in a graphics program like Photoshop. This image contained all the &#8220;steel&#8221; dials, gauges, and labels, but with no data.</p>
</li>



<li>
<p><strong>The Data:</strong> They would then use this image as a background in an HTML file. The magic happened by using Cumulus&#8217;s simple but powerful templating engine. Users would strategically place Cumulus&#8217;s special &#8220;web tags&#8221; (e.g., <code>&lt;#temp&gt;</code>, <code>&lt;#windspeed&gt;</code>, <code>&lt;#press&gt;</code>) over the blank areas on the gauges.</p>
</li>
</ol>



<p>When Cumulus processed this file, it would replace the tags with the live weather data. The software would then automatically upload the updated HTML file and the background image to the user&#8217;s web server.</p>



<p>Today, the Steel Gauges are perhaps a time capsule of a specific design era. They were built for a desktop-first world and were not responsive, often looking cluttered on mobile screens. As web design shifted towards minimalism, flat design, and mobile-first principles, the Steel Gauge aesthetic was largely superseded by clean, abstract, and data-dense interfaces like the Belchertown skin for WeeWX, which we come to next. However, they remain a nostalgic and important step in the evolution of personal weather data visualisation.</p>



<h3 class="wp-block-heading">The Current: Between Open and Closed Systems</h3>



<p>Standing down our Weather Display and Cumulus systems, we moved onto software known as WeeWX, running on a Raspberry Pi and sending data to a variety of online sources. It remains the system we use today. <strong>WeeWX</strong> (often stylised as weewx ) is a foundational piece of software in the modern personal weather station (PWS) world, but it&#8217;s fundamentally different from its predecessors. It is best understood not as a single application, but as an open-source software engine for collecting, processing, and displaying weather data.</p>



<p>It was created earlier than we at first thought &#8211; by Tom Keffer, with initial development beginning in the winter of 2008, with the first official release of WeeWX in 2009.</p>



<p>WeeWX is written entirely in Python and designed to run on Linux-based systems. This makes it the go-to choice for hobbyists who want to run their weather station on a low-power, single-board computer like a Raspberry Pi, operating 24/7 with minimal energy consumption, making it a notable move away from our previous power-hungry Windows machines.</p>



<p>The core philosophy is based around modularity and extensibility. It treats the different parts of managing a weather station as separate, interconnected components:</p>



<ol class="wp-block-list">
<li>
<p><strong>The Engine:</strong> At its heart, weewx runs a main loop that communicates directly with the weather station hardware. It polls the station every few seconds for live data (like wind speed) and stores this information in a database (typically SQLite by default, though others are supported).</p>
</li>



<li>
<p><strong>The Reporting Cycle:</strong> At a regular, user-defined interval (the &#8220;archive interval,&#8221; often every 5 minutes), the reporting engine wakes up. It pulls the latest data from the database and uses it to generate reports.</p>
</li>



<li>
<p><strong>Skins and Generators:</strong> This is where the user-facing magic happens. A &#8220;skin&#8221; in weewx is a complete template for a website, containing HTML files, CSS, images, and configuration settings. Using the powerful Cheetah templating engine, weewx fills these templates with data to generate static HTML pages. It can also run &#8220;generators&#8221; that push data to public services like Weather Underground, PWSWeather, and in our case custom MQTT brokers &#8211; this is key as it opens up the new world of Vibe Coding, which we come to next.</p>
</li>



<li>
<p><strong>Extensibility:</strong> The most powerful feature of weewx is its architecture, which is designed to be extended. Users can write their own services in Python to calculate new variables (e.g., custom fire danger indices), add new sensor types, or create entirely new report formats. This makes it a flexible platform for tinkerers and data enthusiasts.</p>
</li>
</ol>



<p>Out of the box, weewx comes with a simple, functional skin. However, its skinning architecture is has been key to community projects. The most used by far is the <strong>Belchertown skin</strong>, created by Pat O&#8217;Brien. First gaining widespread popularity around early 2019, Belchertown provides a clean, modern, mobile-responsive interface with dark mode, interactive charts, and real-time streaming updates via MQTT. It has become the de-facto &#8220;face&#8221; of weex for many users and perfectly embodies the modernist design principles of clarity and function.</p>



<figure class="wp-block-image size-large"><img decoding="async" src="https://www.digitalurban.org/wp-content/uploads/2025/08/c2962b81-6ed6-4e7d-94f4-e1d967c6d90d_2078x1310.png" alt=""/></figure>



<p>At the polar opposite of weewx are the more propoietry systems that are run by the weather station hardware providers &#8211; Davis, being one key example with their live data system via Weatherlink.</p>



<p>Davis Instruments is a respected name in the personal weather station market, occupying the premium &#8220;prosumer&#8221; space. Based in California, the company is renowned for producing accurate, durable, and reliable hardware that is arguably considered a gold standard by serious hobbyists, educators, and agricultural professionals.</p>



<p>Their flagship products are the <strong>Vantage Pro2</strong> (their expandable, top-of-the-line model) and the <strong>Vantage Vue</strong> (a more compact, all-in-one unit). For decades, the main challenge for Davis owners was getting the rich data from this excellent hardware onto a computer and the internet &#8211; we have run their Vantage Pro line since the 2000’s and now use weewx &#8211; but they do have their own ‘out of the box’ system for people who do not want to tinker with a Raspberry Pi.</p>



<p>Originally, connecting a Davis station required a piece of hardware called the <strong>WeatherLink Data Logger</strong>. This was a small module that slotted into the back of the weather station console, attached via a serial or USB cable to a PC. To get data online 24/7, a user had to leave a computer running constantly with the WeatherLink PC software. The data logger itself was a one-time hardware purchase, costing around £150-£250 &#8211; our data logger used to plug into our Windows machine and Weather Display.</p>



<figure class="wp-block-image size-large"><img decoding="async" src="https://www.digitalurban.org/wp-content/uploads/2025/08/e9477f3e-033f-4101-910c-e235f1689a95_832x802.png" alt=""/></figure>



<p>The modern solution is thankfully far more elegant. Davis replaced the data logger with their <strong>WeatherLink Live </strong>unit in 2019. This small, standalone box acted as an internet bridge. It independently listened for the radio signals from the outdoor sensors and sent the data directly to their WeatherLink Cloud. This was the first device to eliminate the need for a console to be connected to a computer &#8211; it basically took the computer out of the workflow.</p>



<p>This was superseded by the <strong>WeatherLink Console (model 6313)</strong> in early 2023, updating the previous and notably dated previous iteration.</p>



<figure class="wp-block-image size-large"><img decoding="async" src="https://www.digitalurban.org/wp-content/uploads/2025/08/c9222c82-63e0-4ee7-9c73-3f9074cdac56_1378x1040.png" alt=""/></figure>



<p>Today, WeatherLink refers to the entire cloud-based ecosystem (<code>WeatherLink.com</code> and the mobile app). When you buy and connect a WeatherLink Live device, you get access to this platform. It allows you to view your data from anywhere, see historical charts, and share your station publicly.</p>



<p>The web-based dashboard is, however, slightly ‘clunky’ and arguably badly designed:</p>



<figure class="wp-block-image size-large"><img decoding="async" src="https://www.digitalurban.org/wp-content/uploads/2025/08/10cac172-5be4-4dac-84e6-19e93c18ee95_2858x1250.png" alt=""/></figure>



<p>It also operates on a tiered subscription model, and to view your data in real-time, costs.</p>



<ol class="wp-block-list">
<li><p><strong>Basic Tier (Free):</strong> When you purchase your hardware (e.g., a Vantage Vue station + a WeatherLink Live device), you get the Basic tier for free. This includes:</p>
<ul class="wp-block-list">
<li>
<p>Your current, live data updated every minute.</p>
</li>



<li>
<p>A 24-hour chart of your data.</p>
</li>



<li>
<p>The ability to see your data on the app and website.</p>
</li>
</ul>
</li>



<li><p><strong>Pro Tier (Paid):</strong> This is the most common upgrade for enthusiasts. For a recurring fee, it unlocks much deeper access to your own data.</p>
<ul class="wp-block-list">
<li>
<p><strong>Cost:</strong> Approximately <strong>$3.95/month</strong> or <strong>$42.50/year</strong> (with prices subject to change and regional variation).</p>
</li>



<li><p><strong>Features:</strong></p>
<ul class="wp-block-list">
<li>
<p>Access to your full, detailed historical data archive.</p>
</li>



<li>
<p>Advanced, customisable charting tools to analyse your history.</p>
</li>



<li>
<p>More frequent &#8220;live&#8221; data updates on the web (every 2.5 seconds).</p>
</li>



<li>
<p>The ability to download your data archive as a CSV file.</p>
</li>
</ul>
</li>
</ul>
</li>
</ol>



<p>As such, we still have our Davis Vantage Pro plugged into a WeeWX system, which enables the transmission of data through an MQTT server and bypasses any paywalls to view our own data.</p>



<h3 class="wp-block-heading">Towards Personal Templates with Vibe Coding</h3>



<p>This would normally leave us with the Belchertown Skin, and while excellent, the itch to edit and innovate is always strong, and with it the desire to pull in increasingly customised data feeds, pulling in multiple sources of data to gain a better overview of the current environmental conditions. This would normally require a good understanding of data structures, application protocol interfaces, cascading style sheets, JavaScript and perhaps a bit of Firebase and databases. All of course are good to know and learn but if you want a new look to your data and only have a hour free then Vibe Coding is the current route to take. As in <a href="https://open.substack.com/pub/digitalurban/p/vibe-coding-from-ios-apps-to-an-asteroid?r=u7cv&amp;utm_campaign=post&amp;utm_medium=web&amp;showWelcomeOnShare=true">our previous substack post</a>, the term ‘Vibe Coding’ was defined Andrej Karpathy, a co-founder at OpenAI in Early 2025. The basic idea is to rely entirely on Large Language Models &#8211; LLMs &#8211; and code by using only natural language prompting, rather than writing the code yourself. At the moment we are exploring this new way to develop Weather Dashboards and are in the process of adding examples to our GitHub.</p>



<figure class="wp-block-image size-large"><img decoding="async" src="https://www.digitalurban.org/wp-content/uploads/2025/08/97dbcfce-e0bd-45a3-9545-004e2794b0b8_2172x1434.png" alt=""/></figure>



<p>Our first example (see <a href="https://digitalurban.github.io/VibeWeatherDashboards/mixed_dashboard.html">https://digitalurban.github.io/VibeWeatherDashboards/mixed_dashboard.html</a>), pictured above, was created using Gemini 2.5 Pro, which is currently available for free for a month. The Pro version provides sufficient usage to create an unlimited number of dashboards. Vibe Coding is good &#8211; but it&#8217;s not that good, it won’t create the dashboard above in a single prompt, it takes a number of iterations, starting small and building up. It was built using the Canvas feature, which allows both a view of the code and a live preview, making it quick and easy to make changes. For example, our first prompt into Gemini was ‘make a 5-day forecast for ‘our area’ using a free weather api and use flat icons’. This created the 5-day forecast, using the Open-Meteo API, we subsequently pointed Gemini to our weewx data feed and asked it to use the same icon style to provide a dashboard using the key weather data indicators of Temperature, Wind, Rain, Pressure and Solar. Once that was working, with a few edits back and forth, we then added the coloured background, which changes colour according to the outside temperature, ranging from a dark blue for -10 °C through to a deep red for 35 degrees and above.</p>



<p>At the moment, we have it running on an old iPad, which we have mounted in a frame, sitting on a bookshelf in the corner of the room:</p>



<figure class="wp-block-image size-large"><img decoding="async" src="https://www.digitalurban.org/wp-content/uploads/2025/08/d5d36992-40bc-4b19-bfc3-1e2f02bf3bb5_4032x3024.jpeg" alt=""/></figure>



<p>Vibe coding has also enabled us to explore the creation of AI Weather Landscape dashboards, which take the raw output of the UK Met Office forecast and send it to the Google Vertex AI platform to interpret it as an image of an English Landscape, twice a day.</p>



<figure class="wp-block-image size-large"><img decoding="async" src="https://www.digitalurban.org/wp-content/uploads/2025/08/04e83eb9-9581-4337-85c1-34f6ea5b0c07_2878x1502.png" alt=""/></figure>



<p>Finally, Vibe Coding has allowed us to experiment with real-time graphing, something that harks back to Cumulus, as their templates integrated a series of graphs as part of a drop-down menu. Our graphing displays data in real-time over a period of 24 hours, allowing trends to be visualised and also the graphs to update as new data points come in.</p>



<figure class="wp-block-image size-large"><img decoding="async" src="https://www.digitalurban.org/wp-content/uploads/2025/08/5ff88b88-0d27-49ea-8a91-e5ebb001582e_2526x1464.png" alt=""/></figure>



<p>The creation of a real-time graphing required the setting up of Firebase &#8211; something which is not overly self-explanatory. However, using Vibe Coding it only took an hour and a half from knowing little to nothing, to have a full system set up and running &#8211; it is all in the human language prompts and taking things in small steps. Our first prompt was ‘we have this data feed (insert mqtt feed link) and want to view it as a real-time graph, probably using Firebase, can you show us how to set it up and provide me with full code to view the data on a webpage’ &#8211; this was 6 months ago using ChatGPT, things move rapdily in this space and now there is <a href="https://firebase.google.com/docs/studio">Firebase Studio</a> which makes it even easier to get up and running.</p>



<p>Having been using and making weather dashboards in 25 years it is only in the last 6 months with the invention of Vibe Coding that innovation has speeded up. We have moved from clunky Windows PC looking interfaces through Flash, skeuomorphism, flat designs and now into hyper-customised dashboards using vibe computing. Yet there is one dashboard that I have kept looking at over the years and so far have been unable to replicate (mainly due to copyright issues, but also the code) &#8211; and that is an online version of the classic Intromet Climatica Weather System.</p>



<figure class="wp-block-image size-large"><img decoding="async" src="https://www.digitalurban.org/wp-content/uploads/2025/08/0ad7a09e-94b3-4f51-80fb-4ca5b437fae1_2126x996.png" alt=""/></figure>



<p>It is perhaps the ultimate digital-analogue physical display, and one that is likely on every weather data enthusiast&#8217;s wish list. While the physical system remains out of reach for us, the developer over at <a href="https://weather.wilmslowastro.com/test/instromet/climatica/climatica.php">Wimslow Weather has made an online version</a> (hidden away under his developer section) and it is lovely:</p>



<figure class="wp-block-image size-large"><img decoding="async" src="https://www.digitalurban.org/wp-content/uploads/2025/08/51199862-05f6-4d50-bc90-c07c3df461fc_2862x1354.png" alt=""/></figure>



<p>Sure, it&#8217;s full on skeuomorphism &#8211; but the tween on the wind direction and wind speed is one of the best we have seen &#8211; so despite having access to the new opportunities of AI, it&#8217;s a physical design from a small <a href="https://instromet.co.uk/climatica-weather-station/">British company, Instromet</a>, that somehow still remains the best, in our view.</p>



<p>We would love to know what dashboard you like or us, do tell us in the comments, and if you like this article, the subscribe link is of course below.</p>
<p>The post <a href="https://www.digitalurban.org/blog/2025/07/25/chasing-the-tween-my-25-year-obsession-with-weather-data/">Chasing the Tween: My 25-Year Obsession with Weather Data</a> appeared first on <a href="https://www.digitalurban.org">Digital Urban</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Enhancing Live Weather Monitoring with MQTT and Chart.js</title>
		<link>https://www.digitalurban.org/blog/2024/06/27/enhancing-live-weather-monitoring-with-mqtt-and-chart-js/</link>
		
		<dc:creator><![CDATA[Andy]]></dc:creator>
		<pubDate>Thu, 27 Jun 2024 15:10:06 +0000</pubDate>
				<category><![CDATA[data]]></category>
		<category><![CDATA[Data Visualisation]]></category>
		<category><![CDATA[Weather]]></category>
		<category><![CDATA[Weather (Live)]]></category>
		<category><![CDATA[Weather Display]]></category>
		<category><![CDATA[Data]]></category>
		<category><![CDATA[mqtt]]></category>
		<guid isPermaLink="false">https://www.digitalurban.org/?p=7816</guid>

					<description><![CDATA[<p>Introduction Viewing real-time data from a personal weather station such as a Davis Vantage Pro, a Tempest, or an EcoWhitt device can be complex. However, the majority of systems that...</p>
<p>The post <a href="https://www.digitalurban.org/blog/2024/06/27/enhancing-live-weather-monitoring-with-mqtt-and-chart-js/">Enhancing Live Weather Monitoring with MQTT and Chart.js</a> appeared first on <a href="https://www.digitalurban.org">Digital Urban</a>.</p>
]]></description>
										<content:encoded><![CDATA[<h2></h2>
<h3>Introduction</h3>
<p>Viewing real-time data from a personal weather station such as a Davis Vantage Pro, a Tempest, or an EcoWhitt device can be complex. However, the majority of systems that process weather data, such as Weather Display, Weewx, or CumlusMx, all have the ability to output MQTT data. This data can be used to display a real-time graph of the data, keeping you engaged with the latest weather updates, and supplemented with any other data which is MQTT-based.</p>
<p>With this in mind, we&#8217;ve developed a live weather monitoring dashboard as an illustrative example. This dashboard uses MQTT for real-time data updates and Chart.js for dynamic visualization. We&#8217;ve also included a visual indicator for connection status and a brief pulse effect to notify when new data arrives, enhancing the user experience.</p>
<p><img fetchpriority="high" decoding="async" class=" wp-image-7820 aligncenter" src="https://www.digitalurban.org/wp-content/uploads/2024/06/Screenshot-2024-06-27-at-15.48.35-300x185.png" alt="MQTT Weather Dashboard" width="600" height="370" srcset="https://www.digitalurban.org/wp-content/uploads/2024/06/Screenshot-2024-06-27-at-15.48.35-300x185.png 300w, https://www.digitalurban.org/wp-content/uploads/2024/06/Screenshot-2024-06-27-at-15.48.35-1024x631.png 1024w, https://www.digitalurban.org/wp-content/uploads/2024/06/Screenshot-2024-06-27-at-15.48.35-768x473.png 768w, https://www.digitalurban.org/wp-content/uploads/2024/06/Screenshot-2024-06-27-at-15.48.35-1536x946.png 1536w, https://www.digitalurban.org/wp-content/uploads/2024/06/Screenshot-2024-06-27-at-15.48.35-2048x1261.png 2048w" sizes="(max-width: 600px) 100vw, 600px" /></p>
<p>You can view it live at: <a href="https://finchamweather.co.uk/weathergraph.htm">https://finchamweather.co.uk/weathergraph.htm</a></p>
<p>The data populates as the page loads &#8211; we could of course back load it via a database link, but the aim was to simply use MQTT and have a graphing system that streams in data, its a work in progress but here is how we got it working:</p>
<h3>Setting Up the Environment</h3>
<p>Before we dive into the code, ensure you have the following libraries included in your HTML:</p>
<ul>
<li>Paho MQTT: for MQTT protocol handling &#8211; our MQTT feed is open to use as a test, replace this with your own MQTT details in the main code.</li>
<li>Chart.js: for creating dynamic charts</li>
<li>Chart.js adapter for date-fns: for handling time scales in charts</li>
</ul>
<h3>Initial HTML Setup</h3>
<p>We&#8217;ll start by setting up the basic HTML structure. This includes elements for displaying the connection status, forecast, weather statistics, and the weather chart.</p>
<pre><code>&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;
&lt;head&gt;
    &lt;meta charset="UTF-8"&gt;
    &lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&gt;
    &lt;meta name="apple-mobile-web-app-capable" content="yes"&gt;
    &lt;meta name="apple-mobile-web-app-status-bar-style" content="black"&gt;
    &lt;title&gt;Live Weather Graph&lt;/title&gt;
    &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/paho-mqtt/1.0.1/mqttws31.js"&gt;&lt;/script&gt;
    &lt;script src="https://cdn.jsdelivr.net/npm/chart.js"&gt;&lt;/script&gt;
    &lt;script src="https://cdn.jsdelivr.net/npm/chartjs-adapter-date-fns"&gt;&lt;/script&gt;
    &lt;style&gt;
        body {
            font-family: Arial, sans-serif;
            margin: 20px;
        }
        #mqttStatus {
            margin-bottom: 20px;
            text-align: left;
            font-size: 1.2em;
        }
        .dot {
            height: 20px;
            width: 20px;
            border-radius: 50%;
            display: inline-block;
        }
        .green {
            background-color: green;
        }
        .red {
            background-color: red;
        }
        .orange {
            background-color: orange;
        }
        .pulse-once {
            animation: pulse-once 1s;
        }
        @keyframes pulse-once {
            0% { transform: scale(1); }
            50% { transform: scale(1.2); }
            100% { transform: scale(1); }
        }
        #forecast {
            margin-bottom: 20px;
            text-align: left;
            font-size: 1.2em;
            font-weight: bold;
        }
        #stats {
            display: flex;
            justify-content: center;
            gap: 20px;
            margin-bottom: 20px;
            font-size: 1.2em;
            font-weight: bold;
        }
        #stats div {
            padding: 10px 20px;
            border: 1px solid #ccc;
            border-radius: 8px;
            box-shadow: 2px 2px 12px #aaa;
            background-color: #f9f9f9;
        }
        canvas {
            border: 1px solid #ccc;
            box-shadow: 2px 2px 12px #aaa;
        }
    &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;div id="mqttStatus"&gt;&lt;span id="connectionDot" class="dot red"&gt;&lt;/span&gt; mqtt: disconnected&lt;/div&gt;
    &lt;div id="forecast"&gt;Forecast: Loading...&lt;/div&gt;
    &lt;div id="stats"&gt;
        &lt;div id="maxWindSpeed"&gt;Max Wind Speed: 0 mph&lt;/div&gt;
        &lt;div id="maxTemp"&gt;Max Temperature: 0 °C&lt;/div&gt;
        &lt;div id="minTemp"&gt;Min Temperature: 0 °C&lt;/div&gt;
        &lt;div id="maxPressure"&gt;Max Pressure: 0 mbar&lt;/div&gt;
        &lt;div id="minPressure"&gt;Min Pressure: 0 mbar&lt;/div&gt;
    &lt;/div&gt;
    &lt;canvas id="weatherChart" width="800" height="400"&gt;&lt;/canvas&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre>
<h3>Connecting to MQTT</h3>
<p>Next, we set up the MQTT connection. The MQTT client will connect to the broker, subscribe to the necessary topics, and handle messages when they arrive.</p>
<pre><code>// MQTT connection settings
var mqtt;
var reconnectTimeout = 2000;
var host = "mqtt.cetools.org";
var port = location.protocol === 'https:' ? 8081 : 8080;
var options = {
    timeout: 3,
    onSuccess: onConnect,
    onFailure: onFailure,
    useSSL: location.protocol === 'https:',
};
var clientID = "clientID" + parseInt(Math.random() * 100);

function updateConnectionStatus(status) {
    const dot = document.getElementById("connectionDot");
    if (status === "connected") {
        dot.className = "dot green";
        document.getElementById("mqttStatus").innerHTML = `&lt;span class="dot green" id="connectionDot"&gt;&lt;/span&gt; mqtt: connected`;
    } else if (status === "disconnected") {
        dot.className = "dot red";
        document.getElementById("mqttStatus").innerHTML = `&lt;span class="dot red" id="connectionDot"&gt;&lt;/span&gt; mqtt: disconnected`;
    } else if (status === "reconnecting") {
        dot.className = "dot orange";
        document.getElementById("mqttStatus").innerHTML = `&lt;span class="dot orange" id="connectionDot"&gt;&lt;/span&gt; mqtt: reconnecting`;
    }
}

function pulseDot() {
    const dot = document.getElementById("connectionDot");
    dot.classList.add("pulse-once");
    setTimeout(() =&gt; {
        dot.classList.remove("pulse-once");
    }, 1000); // Duration of the pulse-once animation
}

function onFailure(message) {
    console.log("Connection Attempt to Host " + host + " Failed: ", message.errorMessage);
    updateConnectionStatus("disconnected");
    setTimeout(MQTTconnect, reconnectTimeout);
}

function onConnect() {
    console.log("Connected ");
    updateConnectionStatus("connected");
    mqtt.subscribe("personal/ucfnaps/downhamweather/loop");
    mqtt.subscribe("personal/ucfnaps/eink/met");
}

function MQTTconnect() {
    console.log("Connecting to " + host + " on port " + port);
    updateConnectionStatus("reconnecting");
    mqtt = new Paho.MQTT.Client(host, port, clientID);
    mqtt.onMessageArrived = onMessageArrived;
    mqtt.onConnectionLost = function(responseObject) {
        if (responseObject.errorCode !== 0) {
            console.log("Connection Lost: " + responseObject.errorMessage);
            updateConnectionStatus("disconnected");
            setTimeout(MQTTconnect, reconnectTimeout);  // Attempt to reconnect
        }
    };
    mqtt.connect(options);
}

window.onload = function() {
    MQTTconnect();
}
</code></pre>
<h3>Handling Incoming Messages</h3>
<p>When messages arrive, we process the data and update the chart. We also update the connection dot to pulse briefly, indicating new data has been received.</p>
<pre><code>let lastUpdate = Date.now();  // Initialize to current time
let firstUpdate = true;  // Flag to ensure first update happens immediately

let maxWindSpeed = 0;
let maxTemp = -Infinity;
let minTemp = Infinity;
let maxPressure = -Infinity;
let minPressure = Infinity;

function updateWindSpeed(windSpeed, timestamp) {
    weatherChart.data .labels.push(timestamp);
    weatherChart.data.datasets[0].data.push(windSpeed);

    // Update max wind speed
    if (windSpeed &gt; maxWindSpeed) {
        maxWindSpeed = windSpeed;
        document.getElementById('maxWindSpeed').innerText = `Max Wind Speed: ${maxWindSpeed} mph`;
    }

    // Limit the number of data points to keep the chart responsive
    if (weatherChart.data.labels.length &gt; 1440) { // Assuming 1 data point per minute, keep 24 hours of data
        weatherChart.data.labels.shift();
        weatherChart.data.datasets[0].data.shift();
    }

    weatherChart.update();
}

function updateOtherMetrics(temperature, solarRadiation, rainAmount, pressure, timestamp) {
    weatherChart.data.datasets[1].data.push({x: timestamp, y: temperature});
    weatherChart.data.datasets[2].data.push({x: timestamp, y: solarRadiation});
    weatherChart.data.datasets[3].data.push({x: timestamp, y: rainAmount &gt; 0 ? rainAmount : null});
    weatherChart.data.datasets[4].data.push({x: timestamp, y: pressure});

    // Update max and min temperature
    if (temperature &gt; maxTemp) {
        maxTemp = temperature;
        document.getElementById('maxTemp').innerText = `Max Temperature: ${maxTemp} °C`;
    }
    if (temperature &lt; minTemp) { minTemp = temperature; document.getElementById('minTemp').innerText = `Min Temperature: ${minTemp} °C`; } // Update max and min pressure if (pressure &gt; maxPressure) {
        maxPressure = pressure;
        document.getElementById('maxPressure').innerText = `Max Pressure: ${maxPressure} mbar`;
    }
    if (pressure &lt; minPressure) { minPressure = pressure; document.getElementById('minPressure').innerText = `Min Pressure: ${minPressure} mbar`; } // Limit the number of data points to keep the chart responsive if (weatherChart.data.labels.length &gt; 1440) { // Assuming 1 data point per minute, keep 24 hours of data
        weatherChart.data.datasets[1].data.shift();
        weatherChart.data.datasets[2].data.shift();
        weatherChart.data.datasets[3].data.shift();
        weatherChart.data.datasets[4].data.shift();
    }

    weatherChart.update();
}

function updateForecast(forecast) {
    document.getElementById('forecast').innerText = `Forecast: ${forecast}`;
}

function onMessageArrived(message) {
    console.log("Message Arrived: " + message.destinationName + " : " + message.payloadString);
    if (message.destinationName === "personal/ucfnaps/downhamweather/loop") {
        const data = JSON.parse(message.payloadString);
        const windSpeed = data['windSpeed_mph'];  // Adjust this key according to your data structure
        const temperature = data['outTemp_C'];  // Adjust this key according to your data structure
        const solarRadiation = data['radiation_Wpm2'];  // Adjust this key according to your data structure
        const rainAmount = data['dayRain_mm'];  // Adjust this key according to your data structure
        const pressure = data['pressure_mbar'];  // Adjust this key according to your data structure

        const nowTimestamp = new Date();

        // Update wind speed every time
        updateWindSpeed(windSpeed, nowTimestamp);

        if (firstUpdate || Date.now() - lastUpdate &gt;= 60000) {
            // Update other metrics every minute
            updateOtherMetrics(temperature, solarRadiation, rainAmount, pressure, nowTimestamp);
            lastUpdate = Date.now();
            firstUpdate = false;  // Ensure subsequent updates follow the interval
        }

        // Pulse the dot when new data arrives
        pulseDot();
    } else if (message.destinationName === "personal/ucfnaps/eink/met") {
        const forecast = message.payloadString;
        updateForecast(forecast);
    }
}
</code></pre>
<h3>Chart.js Setup</h3>
<p>Now, let&#8217;s configure Chart.js to visualize the weather data. We will use multiple datasets to display wind speed, temperature, solar radiation, rain amount, and pressure.</p>
<pre><code>// Chart.js setup
const ctx = document.getElementById('weatherChart').getContext('2d');
const weatherChart = new Chart(ctx, {
    type: 'line',
    data: {
        labels: [],  // Time labels
        datasets: [{
            label: 'Wind Speed (mph)',
            data: [],
            borderColor: 'rgba(75, 192, 192, 1)',
            borderWidth: 3,
            fill: false,
            yAxisID: 'y-axis-1',
            tension: 0.1
        },
        {
            label: 'Temperature (°C)',
            data: [],
            borderColor: 'rgba(255, 99, 132, 1)',
            borderWidth: 3,
            fill: false,
            yAxisID: 'y-axis-2',
            tension: 0.1
        },
        {
            label: 'Solar Radiation (W/m²)',
            data: [],
            borderColor: 'rgba(255, 206, 86, 1)',
            borderWidth: 3,
            fill: false,
            yAxisID: 'y-axis-3',
            tension: 0.1
        },
        {
            label: 'Rain Amount (mm)',
            data: [],
            borderColor: 'rgba(54, 162, 235, 1)',
            borderWidth: 3,
            fill: false,
            yAxisID: 'y-axis-4',
            tension: 0.1
        },
        {
            label: 'Pressure (mbar)',
            data: [],
            borderColor: 'rgba(153, 102, 255, 1)',
            borderWidth: 3,
            fill: false,
            yAxisID: 'y-axis-5',
            tension: 0.1
        }]
    },
    options: {
        responsive: true,
        plugins: {
            legend: {
                position: 'top',
            },
            title: {
                display: true,
                text: 'Live Weather Data'
            },
            decimation: {
                enabled: true,
                algorithm: 'lttb',
                samples: 100,  // Adjust this value as needed for performance
            },
        },
        scales: {
            x: {
                type: 'time',
                time: {
                    unit: 'minute'
                },
                title: {
                    display: true,
                    text: 'Time'
                }
            },
            'y-axis-1': {
                type: 'linear',
                position: 'left',
                beginAtZero: true,
                title: {
                    display: true,
                    text: 'Wind Speed (mph)'
                }
            },
            'y-axis-2': {
                type: 'linear',
                position: 'right',
                beginAtZero: true,
                title: {
                    display: true,
                    text: 'Temperature (°C)'
                },
                grid: {
                    drawOnChartArea: false
                }
            },
            'y-axis-3': {
                type: 'linear',
                position: 'right',
                beginAtZero: true,
                title: {
                    display: true,
                    text: 'Solar Radiation (W/m²)'
                },
                grid: {
                    drawOnChartArea: false
                }
            },
            'y-axis-4': {
                type: 'linear',
                position: 'right',
                beginAtZero: true,
                title: {
                    display: true,
                    text: 'Rain Amount (mm)'
                },
                grid: {
                    drawOnChartArea: false
                }
            },
            'y-axis-5': {
                type: 'linear',
                position: 'right',
                beginAtZero: true,
                title: {
                    display: true,
                    text: 'Pressure (mbar)'
                },
                grid: {
                    drawOnChartArea: false
                }
            }
        },
        interaction: {
            intersect: false,
            mode: 'nearest',
        },
        elements: {
            line: {
                cubicInterpolationMode: 'monotone',
            },
        },
    }
});
</code></pre>
<h3>Conclusion</h3>
<p>By integrating MQTT and Chart.js, it is possible to create a dynamic and real-time weather monitoring dashboard. The connection status indicator provides immediate feedback on the connection state, and the pulsing effect when new data arrives enhances user experience by visually notifying them of updates.</p>
<p>This setup can be further extended by adding more datasets, customizing the chart&#8217;s appearance, or integrating additional sensors. The data of course couple be from any feed, but real-time weather monitoring provides a good example of how IoT and web technologies can be combined to create realtime dashboards.</p>
<p>The post <a href="https://www.digitalurban.org/blog/2024/06/27/enhancing-live-weather-monitoring-with-mqtt-and-chart-js/">Enhancing Live Weather Monitoring with MQTT and Chart.js</a> appeared first on <a href="https://www.digitalurban.org">Digital Urban</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Updated Live Weather Data From London</title>
		<link>https://www.digitalurban.org/blog/2013/03/28/updated-live-weather-data-from-london/</link>
		
		<dc:creator><![CDATA[Andy]]></dc:creator>
		<pubDate>Thu, 28 Mar 2013 09:26:12 +0000</pubDate>
				<category><![CDATA[Projects]]></category>
		<category><![CDATA[Weather (Live)]]></category>
		<category><![CDATA[Weather Display]]></category>
		<category><![CDATA[Weather London]]></category>
		<category><![CDATA[Weather Data London]]></category>
		<guid isPermaLink="false">http://www.digitalurban.org/?p=3073</guid>

					<description><![CDATA[<p>We have updated our live weather page with a number of new features. The page updates every 3 seconds with a live feed from a Davis Vantage Pro 2 on...</p>
<p>The post <a href="https://www.digitalurban.org/blog/2013/03/28/updated-live-weather-data-from-london/">Updated Live Weather Data From London</a> appeared first on <a href="https://www.digitalurban.org">Digital Urban</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>We have updated our <a title="London Live Weather Data" href="http://www.casa.ucl.ac.uk/cumulus/ipad.html">live weather page</a> with a number of new features. The page updates every 3 seconds with a live feed from a Davis Vantage Pro 2 on the roof of 1-19 Torrington Place, just off Tottenham Court Road in London.<br />
<a href="http://www.casa.ucl.ac.uk/cumulus/ipad.html"><img decoding="async" class="wp-image-3074 aligncenter" style="border: 2px solid black;" title="London Weather Data" alt="London Weather Data" src="https://www.digitalurban.org/wp-content/uploads/2013/03/Weatherdials-1.jpg" width="614" height="819" srcset="https://www.digitalurban.org/wp-content/uploads/2013/03/Weatherdials-1.jpg 768w, https://www.digitalurban.org/wp-content/uploads/2013/03/Weatherdials-1-225x300.jpg 225w" sizes="(max-width: 614px) 100vw, 614px" /></a><br />
The weather dials now include:</p>
<ul>
<li>Visual Wind Rose &#8211; to show the average wind direction;</li>
<li>Wind Run &#8211; an odometer style view of the total distance the wind has travelled in the last 24 hours;</li>
<li>UV Index, showing the current UV level for London.</li>
</ul>
<p>The page is optimised for a tablet/mobile view &#8211; <a title="Live London Weather Data" href="http://www.casa.ucl.ac.uk/cumulus/ipad.html">View the live London Weather Dials</a>.</p>
<p>The post <a href="https://www.digitalurban.org/blog/2013/03/28/updated-live-weather-data-from-london/">Updated Live Weather Data From London</a> appeared first on <a href="https://www.digitalurban.org">Digital Urban</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Live Weather Central London: Flash and iPhone</title>
		<link>https://www.digitalurban.org/blog/2008/11/03/live-weather-central-london-flash-and/</link>
					<comments>https://www.digitalurban.org/blog/2008/11/03/live-weather-central-london-flash-and/#comments</comments>
		
		<dc:creator><![CDATA[Andy]]></dc:creator>
		<pubDate>Mon, 03 Nov 2008 18:02:00 +0000</pubDate>
				<category><![CDATA[iphone]]></category>
		<category><![CDATA[London Live Weather]]></category>
		<category><![CDATA[Weather Display]]></category>
		<guid isPermaLink="false">http://digitalurban.net/?p=1547</guid>

					<description><![CDATA[<p>After a few months out of action due to a dodgy anemometer a trip to the roof today has bought our weather station back online. The weather station is located...</p>
<p>The post <a href="https://www.digitalurban.org/blog/2008/11/03/live-weather-central-london-flash-and/">Live Weather Central London: Flash and iPhone</a> appeared first on <a href="https://www.digitalurban.org">Digital Urban</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p><a href="http://www.casa.ucl.ac.uk/weather/"><img decoding="async" style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 272px;" src="http://3.bp.blogspot.com/_ADwvfqkxChw/SQ89erI_CjI/AAAAAAAAB0g/WIZXia81Pqg/s400/weatherlive.png" alt="" id="BLOGGER_PHOTO_ID_5264494086605179442" border="0" /></a><br />After a few months out of action due to a dodgy anemometer a trip to the roof today has bought our weather station back online.</p>
<p>The weather station is located on the roof of <a href="http://maps.google.co.uk/maps?f=q&#038;hl=en&#038;geocode=&#038;q=wc1e7hb&#038;sll=39.090432,-94.583653&#038;sspn=0.842042,1.73996&#038;g=wc1e7hb&#038;ie=UTF8&#038;ll=51.521935,-0.134642&#038;spn=0.002637,0.006797&#038;t=h&#038;z=18">1-19 Torrington Place</a>, just off Tottenham Court Road in Central London, providing a live feed every two seconds.</p>
<p>We also have an ajax powered version formatted for the iPhone &#8211; simply double tap to zoom into each section, again data updates every two seconds:</p>
<p><a href="http://www.casa.ucl.ac.uk/weather/wxindex.php"><img decoding="async" style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer; width: 400px; height: 267px;" src="http://2.bp.blogspot.com/_ADwvfqkxChw/SQ892qHSs0I/AAAAAAAAB0o/0QaO7YWyq2Y/s400/iphoneweather.png" alt="" id="BLOGGER_PHOTO_ID_5264494498646504258" border="0" /></a>Perfect for checking the weather in London live while sitting on the bus (or is that just us?)</p>
<p>View <a href="http://www.casa.ucl.ac.uk/weather/">London&#8217;s Weather Live</a>, or view the <a href="http://www.casa.ucl.ac.uk/weather/wxindex.php">mobileiPhone version</a>.</p>
<p>The post <a href="https://www.digitalurban.org/blog/2008/11/03/live-weather-central-london-flash-and/">Live Weather Central London: Flash and iPhone</a> appeared first on <a href="https://www.digitalurban.org">Digital Urban</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.digitalurban.org/blog/2008/11/03/live-weather-central-london-flash-and/feed/</wfw:commentRss>
			<slash:comments>6</slash:comments>
		
		
			</item>
	</channel>
</rss>
