<?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 Archives - Digital Urban</title>
	<atom:link href="https://www.digitalurban.org/blog/tag/weather/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.digitalurban.org/blog/tag/weather/</link>
	<description>Data, Cities, IoT, Writing, Music and Making Things</description>
	<lastBuildDate>Thu, 13 Nov 2025 12:11:44 +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 Archives - Digital Urban</title>
	<link>https://www.digitalurban.org/blog/tag/weather/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Stepper Motor Linear Data Gauge</title>
		<link>https://www.digitalurban.org/blog/2025/11/13/stepper-motor-linear-data-gauge/</link>
		
		<dc:creator><![CDATA[Andy]]></dc:creator>
		<pubDate>Thu, 13 Nov 2025 12:01:34 +0000</pubDate>
				<category><![CDATA[Making]]></category>
		<category><![CDATA[Data]]></category>
		<category><![CDATA[gauge]]></category>
		<category><![CDATA[iot]]></category>
		<category><![CDATA[stepper]]></category>
		<category><![CDATA[Weather]]></category>
		<guid isPermaLink="false">https://www.digitalurban.org/?p=170079124</guid>

					<description><![CDATA[<p>The latest upload to the Open Gauges Github is a Linear Gauge, using a timing belt to provide a full 1 metre range for the data visualisation. It uses a...</p>
<p>The post <a href="https://www.digitalurban.org/blog/2025/11/13/stepper-motor-linear-data-gauge/">Stepper Motor Linear Data Gauge</a> appeared first on <a href="https://www.digitalurban.org">Digital Urban</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>The latest upload to the <a href="https://github.com/ucl-casa-ce/Open-Gauges/tree/main">Open Gauges Github</a> is a Linear Gauge, using a timing belt to provide</p>
<div id="attachment_170079126" style="width: 210px" class="wp-caption alignright"><img fetchpriority="high" decoding="async" aria-describedby="caption-attachment-170079126" class="wp-image-170079126 size-large" src="https://www.digitalurban.org/wp-content/uploads/2025/11/WindStepperLinear-200x1024.png" alt="Linear Stepper Motor Gauge" width="200" height="1024" srcset="https://www.digitalurban.org/wp-content/uploads/2025/11/WindStepperLinear-200x1024.png 200w, https://www.digitalurban.org/wp-content/uploads/2025/11/WindStepperLinear-300x1536.png 300w, https://www.digitalurban.org/wp-content/uploads/2025/11/WindStepperLinear-400x2048.png 400w, https://www.digitalurban.org/wp-content/uploads/2025/11/WindStepperLinear.png 402w" sizes="(max-width: 200px) 100vw, 200px" /><p id="caption-attachment-170079126" class="wp-caption-text">Linear Stepper Motor Gauge</p></div>
<p>a full 1 metre range for the data visualisation. It uses a stepper motor for precise needle movement, and a limit switch for calibration, it can be adapted to any MQTT data feed and any base mount. The example shown uses a 5cm by 10cm peice of wood, cut to 1 metre length and indicates wind speed from 0 to 60 mph.</p>
<p class="p1">The design uses a stepper motor (like the 28BYJ-48) which offers high-precision, 360-degree movement without the jitter or limited range of a standard servo. The limit switch allows the gauge to &#8220;home&#8221; itself on startup, ensuring the pointer always starts at a known zero position.</p>
<p class="p1">The main code &#8211; <span class="s1">WindStepperTimerBeltwithLimitSwitch.ino</span> in the Github has a distance calibration number, adjust for your range.</p>
<p class="p1"><b>Hardware Components</b></p>
<ul class="ul1">
<li class="li1">Arduino-compatible Board: Any board like an Arduino Uno, Nano, or a NodeMCU.</li>
<li class="li1">Stepper Motor: 28BYJ-48 5V stepper motor.</li>
<li class="li1">Stepper Driver: ULN2003 driver board (which often comes with the 28BYJ-48).</li>
<li class="li1">Limit Switch: A small microswitch to detect the pointers zero position.</li>
<li class="li1">Power Supply: USB.</li>
<li class="li1">Timer Belt <a href="https://www.amazon.co.uk/Timing-Pulley-Tensioner-Torsion-Printer/dp/B0C54ZXM88/ref=sxin_15_pa_sp_search_thematic_sspa?content-id=amzn1.sym.0a6bbb1a-ed2d-4392-adfc-40ed1cfcd8e2%3Aamzn1.sym.0a6bbb1a-ed2d-4392-adfc-40ed1cfcd8e2&amp;crid=L07UDXXKCZFX&amp;cv_ct_cx=timing%2Bbelt%2Bgt2&amp;keywords=timing%2Bbelt%2Bgt2&amp;pd_rd_i=B0C54ZXM88&amp;pd_rd_r=12141bbe-35d0-4c0a-8811-d7f399206de4&amp;pd_rd_w=AVwDb&amp;pd_rd_wg=JG5Mx&amp;pf_rd_p=0a6bbb1a-ed2d-4392-adfc-40ed1cfcd8e2&amp;pf_rd_r=H6T6R7VAGD99FGNPH875&amp;qid=1763028887&amp;sbo=RZvfv%2F%2FHxDF%2BO5021pAnSA%3D%3D&amp;sprefix=timer%2Bbelt%2Bgt2%2Caps%2C99&amp;sr=1-5-ad3222ed-9545-4dc8-8dd8-6b2cb5278509-spons&amp;aref=vwr3X339Nm&amp;sp_csd=d2lkZ2V0TmFtZT1zcF9zZWFyY2hfdGhlbWF0aWM&amp;th=1"><span class="s2">GT2 Timer Belt</span></a></li>
</ul>
<p>It is made to be as simple to build/power as possible but also adatable for a number of senarios.</p>
<p>The github provides the mount for the stepper motor, the pointer (which also joins together the timing belt) the limit switch and the end mount for the pulley. These allow the gauge to be adapted to any size required.</p>
<p>At the moment the gauge is sitting on the wall in our lounge and it has become one of our most used guages. The data updates every minute to show the maximum wind gust and due to the nature of the stepper motor, it provides a smooth movement, almost replicating the gust of wind.</p>
<p>&nbsp;</p>
<p>The post <a href="https://www.digitalurban.org/blog/2025/11/13/stepper-motor-linear-data-gauge/">Stepper Motor Linear Data Gauge</a> appeared first on <a href="https://www.digitalurban.org">Digital Urban</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Just Weather for The Pebble Watch: Making a Data Watch Face</title>
		<link>https://www.digitalurban.org/blog/2025/10/30/just-weather-for-the-pebble-watch-making-a-data-watch-face/</link>
		
		<dc:creator><![CDATA[Andy]]></dc:creator>
		<pubDate>Thu, 30 Oct 2025 12:59:40 +0000</pubDate>
				<category><![CDATA[Apps]]></category>
		<category><![CDATA[copilot]]></category>
		<category><![CDATA[Data]]></category>
		<category><![CDATA[github]]></category>
		<category><![CDATA[Pebble Watch]]></category>
		<category><![CDATA[Weather]]></category>
		<guid isPermaLink="false">https://www.digitalurban.org/?p=170079095</guid>

					<description><![CDATA[<p>The post <a href="https://www.digitalurban.org/blog/2025/10/30/just-weather-for-the-pebble-watch-making-a-data-watch-face/">Just Weather for The Pebble Watch: Making a Data Watch Face</a> appeared first on <a href="https://www.digitalurban.org">Digital Urban</a>.</p>
]]></description>
										<content:encoded><![CDATA[
		<div id="fws_696f9d36ba20b"  data-column-margin="default" data-midnight="dark"  class="wpb_row vc_row-fluid vc_row top-level"  style="padding-top: 0px; padding-bottom: 0px; "><div class="row-bg-wrap" data-bg-animation="none" data-bg-animation-delay="" data-bg-overlay="false"><div class="inner-wrap row-bg-layer" ><div class="row-bg viewport-desktop"  style=""></div></div></div><div class="row_col_wrap_12 col span_12 dark left">
	<div  class="vc_col-sm-12 wpb_column column_container vc_column_container col no-extra-padding inherit_tablet inherit_phone "  data-padding-pos="all" data-has-bg-color="false" data-bg-color="" data-bg-opacity="1" data-animation="" data-delay="0" >
		<div class="vc_column-inner" >
			<div class="wpb_wrapper">
				
<div class="wpb_text_column wpb_content_element " >
	<div class="wpb_wrapper">
		<p>It&#8217;s an exciting time to be a Pebble fan. After years of being kept alive by the dedicated Rebble community, the Pebble is officially back. The <a href="https://store.repebble.com/">new Pebble 2 Duo watches</a> (the black-and-white model) are officially shipping to the first backers, with the high-resolution color Pebble Time 2 set to follow.</p>
<p>So, I decided to make one myself.</p>
<p>&nbsp;</p>
<h2 class="wp-block-heading">Introducing &#8216;Just Weather&#8217;</h2>
<p>I wanted a face that was clean, digital, and gave me all the key data at a glance, formatted to look great on the 144&#215;168 screen of the Pebble 2. I call it <strong>&#8220;Just Weather.&#8221;</strong></p>
<p>It uses the free Open-Meteo API to pull in a ton of useful, hyperlocal data right to your wrist:</p>
<p>&nbsp;</p>
<ul class="wp-block-list">
<li style="list-style-type: none;">
<ul>
<li>Current Location (from your phone&#8217;s GPS)</li>
<li>Temperature</li>
<li>Current Conditions (&#8220;Partly Cloudy,&#8221; &#8220;Rain,&#8221; etc.)</li>
<li>Barometric Pressure &amp; 3-Hour Trend</li>
<li>Wind Speed &amp; Precipitation</li>
<li>&#8230;and of course, the time!</li>
</ul>
</li>
</ul>
<p>&nbsp;</p>
<p>&nbsp;</p>
<h2 class="wp-block-heading">Built with GitHub CoPiliot</h2>
<p>The best part is that the new Pebble development workflow is incredibly modern. I was able to build this using the <strong>CloudPebble IDE</strong>, which now integrates directly with <strong>VS Code in the browser</strong>.</p>
<p>This meant I could use the emerging tools like <strong>GitHub Copilot</strong> to help generate the code and work through the trickiest parts—like making direct HTTPS requests to the weather API, which (after a lot of testing!) we proved is possible from the phone app.</p>
<p>After getting the data, the final step was tweaking the C code to make sure the layout wasn&#8217;t clipped and all the information fit perfectly on the 144&#215;168 screen. It&#8217;s now compatible with watches in the Pebble family, from the original Pebble Time (color) to the new <strong>Pebble 2 Duo</strong> and the upcoming <strong>Pebble Time 2</strong>.</p>
<p>&nbsp;</p>
<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="727" class="wp-image-170079097" src="https://www.digitalurban.org/wp-content/uploads/2025/10/Screenshot-2025-10-30-at-12.49.33-1024x727.png" alt="Pebble Watch Face" srcset="https://www.digitalurban.org/wp-content/uploads/2025/10/Screenshot-2025-10-30-at-12.49.33-1024x727.png 1024w, https://www.digitalurban.org/wp-content/uploads/2025/10/Screenshot-2025-10-30-at-12.49.33-300x213.png 300w, https://www.digitalurban.org/wp-content/uploads/2025/10/Screenshot-2025-10-30-at-12.49.33-768x545.png 768w, https://www.digitalurban.org/wp-content/uploads/2025/10/Screenshot-2025-10-30-at-12.49.33.png 1440w" sizes="(max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">Pebble Watch Face</figcaption></figure>
<p>&nbsp;</p>
<h2 class="wp-block-heading">Available Now</h2>
<p>This project took around 6 hours, with the main issue being that Co-Pilot did not know how to get HTTP requests &#8211; it took me down a lot of rabbit holes, and in the end, it was down to using a simpler call on the data &#8211; XMLHttpRequest. Once this worked it all fell into place and it was simply a case of asking Copilot to add in the data fields, do the geocoding and then take a step back and explain how the code actually works.</p>
<p>If you&#8217;re like me and just want a simple, data-rich weather face, please give it a try&#8230;</p>
<p>&nbsp;</p>
<ul class="wp-block-list">
<li style="list-style-type: none;">
<ul>
<li><strong>Download &#8216;<a href="https://apps.rebble.io/en_US/application/69034d22d004720008412cf1">Just Weather</a>&#8216; from the Rebble Appstore</strong></li>
<li><strong>Check out <a href="https://github.com/digitalurban/just-weather-pebble-watchface">the source code on GitHub</a> for the latest updates &#8211; now includes its own settings page (its become a proper watch face app)&#8230;</strong></li>
</ul>
</li>
</ul>
<p>&nbsp;</p>
<p>&nbsp;</p>
	</div>
</div>




			</div> 
		</div>
	</div> 
</div></div><p>The post <a href="https://www.digitalurban.org/blog/2025/10/30/just-weather-for-the-pebble-watch-making-a-data-watch-face/">Just Weather for The Pebble Watch: Making a Data Watch Face</a> appeared first on <a href="https://www.digitalurban.org">Digital Urban</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Vibe Coding: From iOS Apps to an Asteroid Clock and 3D Cities</title>
		<link>https://www.digitalurban.org/blog/2025/07/16/vibe-coding-from-ios-apps-to-an-asteroid-clock-and-3d-cities/</link>
		
		<dc:creator><![CDATA[Andy]]></dc:creator>
		<pubDate>Wed, 16 Jul 2025 20:38:17 +0000</pubDate>
				<category><![CDATA[3D Modelling]]></category>
		<category><![CDATA[Posts]]></category>
		<category><![CDATA[Gemini]]></category>
		<category><![CDATA[iOS App]]></category>
		<category><![CDATA[LLM]]></category>
		<category><![CDATA[Vibe Coding]]></category>
		<category><![CDATA[Weather]]></category>
		<guid isPermaLink="false">https://www.digitalurban.org/blog/2025/07/16/vibe-coding-from-ios-apps-to-an-asteroid-clock-and-3d-cities/</guid>

					<description><![CDATA[<p>Back in 2023, I wrote a blog post over on DigitalUrban.org creating an app called Frame-IT. It turns out I was using 'Vibe Coding' and it's changed the way I view the creation of almost everything...</p>
<p>The post <a href="https://www.digitalurban.org/blog/2025/07/16/vibe-coding-from-ios-apps-to-an-asteroid-clock-and-3d-cities/">Vibe Coding: From iOS Apps to an Asteroid Clock and 3D Cities</a> appeared first on <a href="https://www.digitalurban.org">Digital Urban</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h4 class="wp-block-heading"><strong>Back in 2023, I wrote a blog post entitled Creating an app called Frame-IT. It turns out I was using &#8216;Vibe Coding&#8217; and it&#8217;s changed the way I view the creation of almost everything&#8230;</strong></h4>



<h2 class="wp-block-heading">Everything Changed</h2>



<p>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.</p>



<p>Back in 2023, I published ‘Frame-IT’, an iOS app on the Apple Store, written in Swift but coded completely in the then-early version of ChatGPT. As I noted on <a href="https://www.digitalurban.org/">DigitalUrban</a>, every app has a story, from the idea through to story boarding, finding a design team, working with in house computer scientists or outsourcing. All of these steps take time, resources and often for the small ‘would be developer’ the obstacles are overwhelming, meaning that the spark of an idea often gets lost.</p>



<p>Yet, everything has changed, the whole landscape of developing, designing and creating has turned on its head. It has reached the point where the spark of an idea can be coded, designed, marketed and launched with the help of Artificial Intelligence. Frame-IT is a very simple app, doing a simple thing, but it came from an idea, a want, a desire to do something which before AI would have got lost in logistics, finding the time of computer scientists, and it would certainly be economically unfeasible.</p>



<h3 class="wp-block-heading">The First Idea</h3>



<p>Frame-IT came about while looking at Samsungs’ Frame Televisions, beyond the normal 4K television they blend into the background by displaying art and making the art look as it is mounted on a white background while also being enclosed in a frame – i.e. like a painting. Samsung does this well and the screens are excellent, but it is limited to art works, leading to the idea that it would be nice to frame websites, specifically ‘data’ based web sites and hang data on walls, data that changes in Realtime. Of course, any screen could be used, but if you simply show data on a screen or monitor, no one notices. If you hang it in a frame, as if its art, people will notice.</p>



<figure class="wp-block-image size-large"><img decoding="async" src="https://www.digitalurban.org/wp-content/uploads/2025/07/51d58c8b-8cc2-49af-a1cb-46048fa08d49_730x584.webp" alt="" /></figure>



<p>The concept was therefore simple, build an application that puts a picture frame around websites, allow users to select which websites to show and if there is more than one, cycle through them, like a dashboard. This would allow small screens, such as iPads, to act as frames and, via AirPlay, devices such as projectors or general screens to gain a look beyond their norm and display websites and data in the same way as hanging art on the wall.</p>



<figure class="wp-block-image size-large"><img decoding="async" src="https://www.digitalurban.org/wp-content/uploads/2025/07/170669e6-abd6-4279-9228-a053860fff00_1536x1009.png" alt="" /></figure>



<p>The problem was, this was an idea, to code it would require knowledge of Swift, a library of ‘picture frames’ and probably a business case to justify the time of resident computer scientists (I work at University College London, so we have a few around) and to be honest it was such a simple idea I’m note sure anyone would listen. So, with the rise of AI, I decided to build it myself, using AI from start to finish, from knowing little about Swift, and only as much about AI as my then twitter feed was full of and reading articles on site such as The Verge.</p>



<p>The app took me two days to build, two days where I was also working, so mainly doing things in-between other tasks, over lunch and a little bit in the evenings. With the initial learning curve out the way, I could rebuild it in a day. The first things I did was sign up to OpenAI to gain access to GPT 4 , which released on March 14th 2023. This allowed me access to the latest version and therefore the most up to date knowledge base, although looking back version 3 would probably have been fine and I could have simply used the free tier. My first prompt was “Can you write me swift code to take a website, centre it and add the image of a picture frame around it’. The app should work full screen, in landscape mode”. I had a sample picture frame (taken from Wikipedia and cutting out the actual image to leave a transparent centre).</p>



<figure class="wp-block-image size-large"><img decoding="async" src="https://www.digitalurban.org/wp-content/uploads/2025/07/764c8b30-9da0-4793-ae7a-be228d42eb10_1000x1000.jpeg" alt="" /></figure>



<p>Within 60 seconds, GPT gave me a section of code and then stopped, it turns out there was a limit in the amount of characters it could respond with. A quick Google search (ironically) showed me that by typing ‘continue’ ChatGPT will continue the code. With this I became a master of cutting and pasting, with the code often taking three continues and code which while sometimes was in code boxes, was also in simply text. It also allowed me to start to understand the layout and nature of Swift, within 30 minutes i had my first app running on an iPad, via Xcode. Simply by cutting and pasting and pressing ‘play’. Not all things worked out, there were often errors, but errors I could cut and paste back into GPT and it would solve them, most of the time.</p>



<p>Each time a milestone was made – a working version, a version with a picture frame in and a website showing, I would save the code as Chat GPT would sometimes break the next version while I was asking for new features. Features such as ‘Add a button to move to the next website’, ‘If there is more than one website, then cycle through them every 60 seconds’ (the websites were hard-coded at this point). Once i had a concept running on my own iPad, I realised it was quite neat and decided to then adapt it so others maybe able to use it. I added a settings page – via ‘Can you delete all the websites I have added and include a settings page, the settings page should be reached via a button and have the ability to add and delete websites, once added they should be saved so the app remembers them when reopened’. This is coding but in the new language – human language.</p>



<p>The picture frames were created in Image Creator by Bing, a search engine I never thought I would use (being a Mac user) but in that last week I had not been near Google. Bing allowed me to type in prompt and get images without any user limits. Simple prompts such as “create me a gold Victorian picture frame, it should be photorealistic with minimum reflections and the centre should be cut out” worked amazingly well, providing me with an almost limitless range of Picture frames to include as part of the assets.</p>



<figure class="wp-block-image size-large"><img decoding="async" src="https://www.digitalurban.org/wp-content/uploads/2025/07/6635903d-3268-45db-b3ce-13e2ed6eb961_2048x1345-1.png" alt="" /></figure>



<p>Not all the picture frames are from AI, a couple are from open source imagery, it felt wrong to cut out the picture, but the frames have some provenance and they were nice to include.</p>



<p>Marketing requires imagery as well – as such I took a very simple picture of my two test iPads and used the ‘PhotoRoom” AI app to transform it to two iPads on a bench with a concrete wall behind, whereas the reality was far from as glamourous.</p>



<p>The <a href="https://apps.apple.com/us/app/frame-it/id6447362214">App is now available via the Apple Store</a>, it even <a href="https://frame-it.framer.website/">has its own website</a> and logo – again designed by AI, designed using <a href="https://looka.com/">Looka</a> and hosted on <a href="https://framer.com/">Framer</a>. So while it worked, it was a little painful with the limited lengths of code in the early version of ChatGPT and the endless cutting and pasting/fixing things &#8211; it was quick, but it still took a notable commitment and time. It is also a very very niche app, but as we get to, thats the point of Vibe Coding.</p>



<h3 class="wp-block-heading">And then Everything Changed Again</h3>



<p>That was 2023 &#8211; late 2024, and everything has changed again, not only the workflow and the tools, but also the ability of the LLMs to Vibe Code, they now work, no more cutting and pasting small chunks of code, everything works. Code comes out ready to go and any errors can be fixed in a complete code base, with notably less errors compared to 2024 . As such, we made another app &#8211; again Vibe Coding, without knowing at the time &#8211; MQTTFrame.</p>



<p>The aim was to build on the concept of FrameIT but allow realtime data intergration directly in the app via MQTT (a lightweight, publish-subscribe network protocol for data) and to make it easy to subscribe to any MQTT topic and display live updates.</p>

<div class="pullquote">
<p>It is a niche thing to want to do, but that’s what Vibe Coding is great for &#8211; building those apps that you want, but perhaps few others do.</p>
</div>

<p>Our aim was to allow:</p>



<ul class="wp-block-list">
<li>
<p><strong>Customizable Frames</strong>: Choose from multiple high-quality decorative frames to complement your home or office décor.</p>
</li>



<li>
<p><strong>Clean and Clear Data Display</strong>: Showcase important data such as temperature, pressure, news, and more with clear typography and layout.</p>
</li>



<li>
<p><strong>Fullscreen Mode</strong>: Tap to seamlessly switch to an immersive fullscreen view, maximizing readability and aesthetics.</p>
</li>



<li>
<p><strong>Easy Management</strong>: Add, edit, and reorder topics quickly through an intuitive interface.</p>
</li>



<li>
<p><strong>Instant Updates</strong>: Receive real-time data updates over MQTT, ensuring you’re always in the know.</p>
</li>
</ul>



<p>And that&#8217;s what we did &#8211; but this time in a day and with everything created in ChatGPT &#8211; icons, graphics, code, marking text, and even walking me back through how to get it on the Apple Store (as it&#8217;s an oddly complex and easily forgotten process).</p>



<figure class="wp-block-image size-large"><img decoding="async" src="https://www.digitalurban.org/wp-content/uploads/2025/07/d4b1fad6-69b7-427f-8106-0d6459dca027_2014x1348.png" alt="" /></figure>



<p>So one day Vibe Coding and an app was taken from concept to ready to publish on the Apple Store &#8211; if you want to try it its currently <a href="https://apps.apple.com/gb/app/mqtt-frame/id6743003699">available for free, on the Apple Store</a></p>



<h3 class="wp-block-heading">Everything Again and Again</h3>



<p>That was the end of 2024, now in mid 2025 and term Vibe Coding has come into common use and Large Language Models are now more than capable of making anything from webpages to apps to writing posts (all of this was, however, written by an actual human; any grammatical errors are of course, intentional). We have now switched from ChatGPT to Google Gemini and use it almost daily to produce and make apps or webpages that perhaps only I want in my life, such as &#8211; an Asteroids Clock, made in 30 minutes (temporarily housed at &#8211; <a href="https://finchamweather.co.uk/astroidsclock.html">https://finchamweather.co.uk/astroidsclock.html</a> &#8211; we will move it to Github soon as we get chance).</p>

<div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;58d654b0-ee21-4fb6-ab79-a58beb898566&quot;,&quot;duration&quot;:null}"> </div>

<p>or a Procedural City Maker (<a href="https://finchamweather.co.uk/proceduralcity.html">https://finchamweather.co.uk/proceduralcity.html)</a></p>

<div class="native-video-embed" data-component-name="VideoPlaceholder" data-attrs="{&quot;mediaUploadId&quot;:&quot;8abdc2e7-b243-40d0-8713-c62e50d0623b&quot;,&quot;duration&quot;:null}"> </div>

<p>or a Weather Dashboard with the forecast made into the image of an English Landscape using data from the API from the UK Met Office:</p>



<figure class="wp-block-image size-large"><img decoding="async" src="https://www.digitalurban.org/wp-content/uploads/2025/07/43df66a8-a90e-4fe8-8edd-279c8d09aaaa_2908x1538.png" alt="" /></figure>



<p>You can view the dashboard live at <a href="https://finchamweather.co.uk/aiweatherimage.html">https://finchamweather.co.uk/aiweatherimage.html</a></p>



<p>All small, niche things that somehow I love and I am happy that Vibe Coding allowed them to exist &#8211; that&#8217;s the magic, Vibe Coding allows you to create anything in your imagination that did not exist to exist, it’s a great time to be making digital things.</p>



<p>If you liked this post, please do subscribe, it gives us a good reason to write another one…</p>


<hr class="wp-block-separator has-css-opacity" />
<div class="subscription-widget-wrap-editor" data-attrs="{&quot;url&quot;:&quot;https://digitalurban.substack.com/subscribe?&quot;,&quot;text&quot;:&quot;Subscribe&quot;,&quot;language&quot;:&quot;en&quot;}" data-component-name="SubscribeWidgetToDOM">
<div class="subscription-widget show-subscribe">
<div class="preamble">
<p class="cta-caption">Thanks for reading Digitalurban’s Substack! Subscribe for free to receive new posts and support my work.</p>
</div>
<form class="subscription-widget-subscribe"><input class="email-input" tabindex="-1" name="email" type="email" placeholder="Type your email…" /><input class="button primary" type="submit" value="Subscribe" />
<div class="fake-input-wrapper">
<div class="fake-input"> </div>
<div class="fake-button"> </div>
</div>
</form></div>
</div><p>The post <a href="https://www.digitalurban.org/blog/2025/07/16/vibe-coding-from-ios-apps-to-an-asteroid-clock-and-3d-cities/">Vibe Coding: From iOS Apps to an Asteroid Clock and 3D Cities</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 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>Creating Art Like Weather Forecast Images with DALL·E 3 and API Data</title>
		<link>https://www.digitalurban.org/blog/2024/04/27/creating-art-like-weather-forecast-images-with-dall%c2%b7e-3-and-api-data/</link>
		
		<dc:creator><![CDATA[Andy]]></dc:creator>
		<pubDate>Sat, 27 Apr 2024 14:12:43 +0000</pubDate>
				<category><![CDATA[Art]]></category>
		<category><![CDATA[Making]]></category>
		<category><![CDATA[Weather]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[Dall-E]]></category>
		<category><![CDATA[FrameTV]]></category>
		<category><![CDATA[MetOffice]]></category>
		<category><![CDATA[Python]]></category>
		<guid isPermaLink="false">https://connected-environments.org/?p=7565</guid>

					<description><![CDATA[<p>The post <a href="https://www.digitalurban.org/blog/2024/04/27/creating-art-like-weather-forecast-images-with-dall%c2%b7e-3-and-api-data/">Creating Art Like Weather Forecast Images with DALL·E 3 and API Data</a> appeared first on <a href="https://www.digitalurban.org">Digital Urban</a>.</p>
]]></description>
										<content:encoded><![CDATA[<div id="fws_696f9d36c23a0"  data-column-margin="default" data-midnight="dark"  class="wpb_row vc_row-fluid vc_row"  style="padding-top: 0px; padding-bottom: 0px; "><div class="row-bg-wrap" data-bg-animation="none" data-bg-animation-delay="" data-bg-overlay="false"><div class="inner-wrap row-bg-layer" ><div class="row-bg viewport-desktop"  style=""></div></div></div><div class="row_col_wrap_12 col span_12 dark left">
	<div  class="vc_col-sm-12 wpb_column column_container vc_column_container col no-extra-padding inherit_tablet inherit_phone "  data-padding-pos="all" data-has-bg-color="false" data-bg-color="" data-bg-opacity="1" data-animation="" data-delay="0" >
		<div class="vc_column-inner" >
			<div class="wpb_wrapper">
				
<div class="wpb_text_column wpb_content_element " >
	<div class="wpb_wrapper">
		<h2>Introduction</h2>
<p>The Met Office, as the national meteorological service for the United Kingdom, provides valuable weather data through its API called DataPoint. This API caters to a wide range of users, including professionals, scientists, students, and amateur developers. One of its notable features is the availability of text-based regional weather forecasts.</p>
<p>However, traditional text-to-image systems often struggle with accurately representing descriptive language. Users often find themselves navigating the complexities of prompt engineering to achieve their desired visual output. However, things are rapidly chaning with the use of AI and OpenAI’s latest release, DALL·E 3, simplifies this process by generating images that align with the provided text.</p>
<p>In this blog post, we’ll explore how to combine Met Office weather forecasts with DALL·E 3 via its API using Python. Our goal? To create captivating landscape imagery that reflects the weather conditions described in the forecast. Our images are then uploaded to our webserver, using FTP for viewing online. If you simply want to create an image, then you can leave the FTP section out.</p>
<h2>The Workflow</h2>
<ol>
<li><strong>Met Office Data Retrieval</strong>:
<ul>
<li>We fetch the weather forecast data from the Met Office DataPoint API. Specifically, we focus on today’s weather conditions. We are using the UK metoffice, but it could be any weather api, from any country, that returns forecast text.</li>
</ul>
</li>
<li><strong>Creating the Image Prompt</strong>:
<ul>
<li>We construct an image prompt that encapsulates the essence of the weather. Our prompt includes the landscape type (e.g., “rural Norfolk landscape”) and the specific weather details obtained from the Met Office. The landscape type can be edited accordingly</li>
</ul>
</li>
<li><strong>DALL·E 3 Image Generation</strong>:
<ul>
<li>Leveraging OpenAI’s DALL·E 3 model, we generate an image based on the provided prompt. The image should realistically depict cloud formations, sunlight, precipitation, and wind effects, all while capturing the mood suggested by the weather.</li>
</ul>
</li>
<li><strong>FTP Upload</strong>:
<ul>
<li>Finally, we upload the generated image to an FTP server for public access.</li>
</ul>
</li>
</ol>
<p>We run the script every 12 hours (ours runs on a Raspberry Pi) with the images archived on the websever &#8211; the gallery below shows some of the images from the last few months:</p>
	</div>
</div>




	<div class="wpb_gallery wpb_content_element clearfix">
		<div class="wpb_wrapper"><div class="wpb_gallery_slidesnectarslider_style" data-onclick="link_no" data-interval="5"><div class="nectar-slider-wrap" style="height: 720px" data-flexible-height="" data-overall_style="classic" data-button-styling="btn_with_count" data-fullscreen="false"  data-full-width="false" data-parallax="false"  id="ns-id-696f9d36c91ea"><div class="swiper-container" style="height: 720px"  data-loop="true" data-height="720" data-bullets="" data-bullet_style="see_through" data-arrows="true" data-desktop-swipe="true" data-settings=""><div class="swiper-wrapper"><div class="swiper-slide" data-bg-alignment="center" data-color-scheme="light" data-x-pos="centered" data-y-pos="middle"><div class="image-bg" style="background-image: url(https://www.digitalurban.org/wp-content/uploads/2024/05/image.jpeg_20240122120033.jpeg);">  &nbsp; </div><span class="ie-fix"></span> </div><!--/swiper-slide--><div class="swiper-slide" data-bg-alignment="center" data-color-scheme="light" data-x-pos="centered" data-y-pos="middle"><div class="image-bg" style="background-image: url(https://www.digitalurban.org/wp-content/uploads/2024/05/image.jpeg_20240121120026.jpeg);">  &nbsp; </div><span class="ie-fix"></span> </div><!--/swiper-slide--><div class="swiper-slide" data-bg-alignment="center" data-color-scheme="light" data-x-pos="centered" data-y-pos="middle"><div class="image-bg" style="background-image: url(https://www.digitalurban.org/wp-content/uploads/2024/05/image.jpeg_20240120120024.jpeg);">  &nbsp; </div><span class="ie-fix"></span> </div><!--/swiper-slide--><div class="swiper-slide" data-bg-alignment="center" data-color-scheme="light" data-x-pos="centered" data-y-pos="middle"><div class="image-bg" style="background-image: url(https://www.digitalurban.org/wp-content/uploads/2024/05/image.jpeg_20240119120029.jpeg);">  &nbsp; </div><span class="ie-fix"></span> </div><!--/swiper-slide--><div class="swiper-slide" data-bg-alignment="center" data-color-scheme="light" data-x-pos="centered" data-y-pos="middle"><div class="image-bg" style="background-image: url(https://www.digitalurban.org/wp-content/uploads/2024/05/image.jpeg_20240118120029.jpeg);">  &nbsp; </div><span class="ie-fix"></span> </div><!--/swiper-slide--><div class="swiper-slide" data-bg-alignment="center" data-color-scheme="light" data-x-pos="centered" data-y-pos="middle"><div class="image-bg" style="background-image: url(https://www.digitalurban.org/wp-content/uploads/2024/05/image.jpeg_20240113120022.jpeg);">  &nbsp; </div><span class="ie-fix"></span> </div><!--/swiper-slide--><div class="swiper-slide" data-bg-alignment="center" data-color-scheme="light" data-x-pos="centered" data-y-pos="middle"><div class="image-bg" style="background-image: url(https://www.digitalurban.org/wp-content/uploads/2024/05/image.jpeg_20240113180024.jpeg);">  &nbsp; </div><span class="ie-fix"></span> </div><!--/swiper-slide--><div class="swiper-slide" data-bg-alignment="center" data-color-scheme="light" data-x-pos="centered" data-y-pos="middle"><div class="image-bg" style="background-image: url(https://www.digitalurban.org/wp-content/uploads/2024/05/image.jpeg_20240114060028.jpeg);">  &nbsp; </div><span class="ie-fix"></span> </div><!--/swiper-slide--><div class="swiper-slide" data-bg-alignment="center" data-color-scheme="light" data-x-pos="centered" data-y-pos="middle"><div class="image-bg" style="background-image: url(https://www.digitalurban.org/wp-content/uploads/2024/05/image.jpeg_20240114120027.jpeg);">  &nbsp; </div><span class="ie-fix"></span> </div><!--/swiper-slide--><div class="swiper-slide" data-bg-alignment="center" data-color-scheme="light" data-x-pos="centered" data-y-pos="middle"><div class="image-bg" style="background-image: url(https://www.digitalurban.org/wp-content/uploads/2024/05/image.jpeg_20240114180024.jpeg);">  &nbsp; </div><span class="ie-fix"></span> </div><!--/swiper-slide--><div class="swiper-slide" data-bg-alignment="center" data-color-scheme="light" data-x-pos="centered" data-y-pos="middle"><div class="image-bg" style="background-image: url(https://www.digitalurban.org/wp-content/uploads/2024/05/image.jpeg_20240115060035.jpeg);">  &nbsp; </div><span class="ie-fix"></span> </div><!--/swiper-slide--><div class="swiper-slide" data-bg-alignment="center" data-color-scheme="light" data-x-pos="centered" data-y-pos="middle"><div class="image-bg" style="background-image: url(https://www.digitalurban.org/wp-content/uploads/2024/05/image.jpeg_20240115120029.jpeg);">  &nbsp; </div><span class="ie-fix"></span> </div><!--/swiper-slide--><div class="swiper-slide" data-bg-alignment="center" data-color-scheme="light" data-x-pos="centered" data-y-pos="middle"><div class="image-bg" style="background-image: url(https://www.digitalurban.org/wp-content/uploads/2024/05/image.jpeg_20240116120025.jpeg);">  &nbsp; </div><span class="ie-fix"></span> </div><!--/swiper-slide--><div class="swiper-slide" data-bg-alignment="center" data-color-scheme="light" data-x-pos="centered" data-y-pos="middle"><div class="image-bg" style="background-image: url(https://www.digitalurban.org/wp-content/uploads/2024/05/image.jpeg_20240117120024.jpeg);">  &nbsp; </div><span class="ie-fix"></span> </div><!--/swiper-slide--><div class="swiper-slide" data-bg-alignment="center" data-color-scheme="light" data-x-pos="centered" data-y-pos="middle"><div class="image-bg" style="background-image: url(https://www.digitalurban.org/wp-content/uploads/2024/05/image.jpeg_20240113060024.jpeg);">  &nbsp; </div><span class="ie-fix"></span> </div><!--/swiper-slide--><div class="swiper-slide" data-bg-alignment="center" data-color-scheme="light" data-x-pos="centered" data-y-pos="middle"><div class="image-bg" style="background-image: url(https://www.digitalurban.org/wp-content/uploads/2024/05/image.jpeg_20240112180032.jpeg);">  &nbsp; </div><span class="ie-fix"></span> </div><!--/swiper-slide--><div class="swiper-slide" data-bg-alignment="center" data-color-scheme="light" data-x-pos="centered" data-y-pos="middle"><div class="image-bg" style="background-image: url(https://www.digitalurban.org/wp-content/uploads/2024/05/image.jpeg_20240112120026.jpeg);">  &nbsp; </div><span class="ie-fix"></span> </div><!--/swiper-slide--><div class="swiper-slide" data-bg-alignment="center" data-color-scheme="light" data-x-pos="centered" data-y-pos="middle"><div class="image-bg" style="background-image: url(https://www.digitalurban.org/wp-content/uploads/2024/05/image.jpeg_20240112060026.jpeg);">  &nbsp; </div><span class="ie-fix"></span> </div><!--/swiper-slide--><div class="swiper-slide" data-bg-alignment="center" data-color-scheme="light" data-x-pos="centered" data-y-pos="middle"><div class="image-bg" style="background-image: url(https://www.digitalurban.org/wp-content/uploads/2024/05/image.jpeg_20240111180025.jpeg);">  &nbsp; </div><span class="ie-fix"></span> </div><!--/swiper-slide--><div class="swiper-slide" data-bg-alignment="center" data-color-scheme="light" data-x-pos="centered" data-y-pos="middle"><div class="image-bg" style="background-image: url(https://www.digitalurban.org/wp-content/uploads/2024/05/image.jpeg_20240111120029.jpeg);">  &nbsp; </div><span class="ie-fix"></span> </div><!--/swiper-slide--><div class="swiper-slide" data-bg-alignment="center" data-color-scheme="light" data-x-pos="centered" data-y-pos="middle"><div class="image-bg" style="background-image: url(https://www.digitalurban.org/wp-content/uploads/2024/05/image.jpeg_20240111060031.jpeg);">  &nbsp; </div><span class="ie-fix"></span> </div><!--/swiper-slide--><div class="swiper-slide" data-bg-alignment="center" data-color-scheme="light" data-x-pos="centered" data-y-pos="middle"><div class="image-bg" style="background-image: url(https://www.digitalurban.org/wp-content/uploads/2024/05/image.jpeg_20240110180025.jpeg);">  &nbsp; </div><span class="ie-fix"></span> </div><!--/swiper-slide--><div class="swiper-slide" data-bg-alignment="center" data-color-scheme="light" data-x-pos="centered" data-y-pos="middle"><div class="image-bg" style="background-image: url(https://www.digitalurban.org/wp-content/uploads/2024/05/image.jpeg_20240110120034.jpeg);">  &nbsp; </div><span class="ie-fix"></span> </div><!--/swiper-slide--><div class="swiper-slide" data-bg-alignment="center" data-color-scheme="light" data-x-pos="centered" data-y-pos="middle"><div class="image-bg" style="background-image: url(https://www.digitalurban.org/wp-content/uploads/2024/05/image.jpeg_20240110060030.jpeg);">  &nbsp; </div><span class="ie-fix"></span> </div><!--/swiper-slide--><div class="swiper-slide" data-bg-alignment="center" data-color-scheme="light" data-x-pos="centered" data-y-pos="middle"><div class="image-bg" style="background-image: url(https://www.digitalurban.org/wp-content/uploads/2024/05/image.jpeg_20240109180026.jpeg);">  &nbsp; </div><span class="ie-fix"></span> </div><!--/swiper-slide--><div class="swiper-slide" data-bg-alignment="center" data-color-scheme="light" data-x-pos="centered" data-y-pos="middle"><div class="image-bg" style="background-image: url(https://www.digitalurban.org/wp-content/uploads/2024/05/image.jpeg_20240109120029.jpeg);">  &nbsp; </div><span class="ie-fix"></span> </div><!--/swiper-slide--><div class="swiper-slide" data-bg-alignment="center" data-color-scheme="light" data-x-pos="centered" data-y-pos="middle"><div class="image-bg" style="background-image: url(https://www.digitalurban.org/wp-content/uploads/2024/05/image.jpeg_20240109060027.jpeg);">  &nbsp; </div><span class="ie-fix"></span> </div><!--/swiper-slide--><div class="swiper-slide" data-bg-alignment="center" data-color-scheme="light" data-x-pos="centered" data-y-pos="middle"><div class="image-bg" style="background-image: url(https://www.digitalurban.org/wp-content/uploads/2024/05/image.jpeg_20240108180023.jpeg);">  &nbsp; </div><span class="ie-fix"></span> </div><!--/swiper-slide--><div class="swiper-slide" data-bg-alignment="center" data-color-scheme="light" data-x-pos="centered" data-y-pos="middle"><div class="image-bg" style="background-image: url(https://www.digitalurban.org/wp-content/uploads/2024/05/image.jpeg_20240108120024.jpeg);">  &nbsp; </div><span class="ie-fix"></span> </div><!--/swiper-slide--><div class="swiper-slide" data-bg-alignment="center" data-color-scheme="light" data-x-pos="centered" data-y-pos="middle"><div class="image-bg" style="background-image: url(https://www.digitalurban.org/wp-content/uploads/2023/12/image.jpeg_20231216122052.jpeg);">  &nbsp; </div><span class="ie-fix"></span> </div><!--/swiper-slide--></div><a href="" class="slider-prev"><i class="icon-salient-left-arrow"></i> <div class="slide-count"> <span class="slide-current">1</span> <i class="icon-salient-right-line"></i> <span class="slide-total"></span> </div> </a>
			     		<a href="" class="slider-next"><i class="icon-salient-right-arrow"></i> <div class="slide-count"> <span class="slide-current">1</span> <i class="icon-salient-right-line"></i> <span class="slide-total"></span> </div> </a><div class="nectar-slider-loading"></div></div></div></div>
		</div> 
	</div> 
<div class="wpb_text_column wpb_content_element " >
	<div class="wpb_wrapper">
		<p>The full code can be seen below, with the latest version available via our GitHub repository.</p>
	</div>
</div>




<div class="wpb_text_column wpb_content_element " >
	<div class="wpb_wrapper">
		<pre class="EnlighterJSRAW" data-enlighter-language="generic"># Import necessary libraries
import ftplib
import requests
from PIL import Image
import io
from bs4 import BeautifulSoup
from datetime import datetime

# Get Met Office Data and Strip Today/Tonight Text
url = 'http://datapoint.metoffice.gov.uk/public/data/txt/wxfcs/regionalforecast/xml/512?key=YOURMETOFFICEAPIKEY'
document = requests.get(url)
soup = BeautifulSoup(document.content, "lxml-xml")

# Extract today's weather forecast
todayraw = soup.find_all("Paragraph", attrs={'title': 'Today:'})
todaystr = str(todayraw)
today = (todaystr.replace('[&lt;Paragraph title="Today:"&gt;', '').replace('&lt;/Paragraph&gt;', '').replace(']', ''))

# Set up OpenAI API key
from openai import OpenAI
client = OpenAI(api_key='YourOpenAIAPIKey')

# FTP server details
ftp_server = 'YourFTPServer'
ftp_username = 'FTPUserName'
ftp_password = 'FTPPassword'

# Specify the type of Norfolk landscape (e.g., rural, coastal, urban)
landscape_type = "rural Norfolk landscape"  # Change this as per your preference

# Create the image prompt
image_prompt = (
    f"A photorealistic single, cohesive scene image of a {landscape_type}, showcasing the following weather conditions: {today}. "
    "The image should realistically depict elements like cloud formations, sunlight or lack thereof, any precipitation, and wind effects. "
    "It should convey the atmosphere and mood suggested by the weather, with appropriate lighting and color tones. No numerical data or text should be included, just a pure visual representation of the weather in the landscape."
)

# Generate an image using OpenAI's DALL·E
def generate_image(prompt):
    response = client.images.generate(prompt=prompt, n=1, model="dall-e-3", quality="standard", style="vivid", size="1792x1024")
    image_url = response.data[0].url
    return image_url

# Function to generate a datestamp
def get_datestamp():
    return datetime.now().strftime("%Y%m%d%H%M%S")

# Modified FTP upload function
def upload_to_ftp(image_url, remote_path):
    with ftplib.FTP(ftp_server) as ftp:
        ftp.login(user=ftp_username, passwd=ftp_password)
        response = requests.get(image_url)
        image = Image.open(io.BytesIO(response.content))
        datestamp = get_datestamp()
        original_image = io.BytesIO()
        image.save(original_image, format='JPEG')
        original_image.seek(0)
        ftp.storbinary(f'STOR {remote_path}_{datestamp}.jpeg', original_image)
        resized_image = image.resize((1792, 1024))
        jpeg_image = io.BytesIO()
        resized_image.save(jpeg_image, format='JPEG')
        jpeg_image.seek(0)
        ftp.storbinary('STOR public_html/image.jpeg', jpeg_image)
        resized_image = image.resize((800, 480))
        jpeg_image = io.BytesIO()
        resized_image.save(jpeg_image, format='JPEG')
        jpeg_image.seek(0)
        ftp.storbinary('STOR public_html/image_eink.jpeg', jpeg_image)

# Generate the image and upload it
image_url = generate_image(image_prompt)
upload_to_ftp(image_url, 'public_html/image.jpeg')
</pre>
	</div>
</div>




			</div> 
		</div>
	</div> 
</div></div>
		<div id="fws_696f9d37075e7"  data-column-margin="default" data-midnight="dark"  class="wpb_row vc_row-fluid vc_row"  style="padding-top: 0px; padding-bottom: 0px; "><div class="row-bg-wrap" data-bg-animation="none" data-bg-animation-delay="" data-bg-overlay="false"><div class="inner-wrap row-bg-layer" ><div class="row-bg viewport-desktop"  style=""></div></div></div><div class="row_col_wrap_12 col span_12 dark left">
	<div  class="vc_col-sm-12 wpb_column column_container vc_column_container col no-extra-padding inherit_tablet inherit_phone "  data-padding-pos="all" data-has-bg-color="false" data-bg-color="" data-bg-opacity="1" data-animation="" data-delay="0" >
		<div class="vc_column-inner" >
			<div class="wpb_wrapper">
				
<div class="wpb_text_column wpb_content_element " >
	<div class="wpb_wrapper">
		<h3>Breaking down the steps in the code &#8211;</h3>
<ol>
<li><strong>Importing Libraries</strong>: We start by importing necessary Python libraries for HTTP requests, image processing, FTP interaction, and data parsing.</li>
<li><strong>Fetching Weather Data</strong>: The script retrieves weather data from the Met Office using an API key. It extracts relevant information using BeautifulSoup and cleans up the output to get the weather forecast for today.</li>
<li><strong>OpenAI API Key</strong>: The OpenAI API key is set up to use the DALL·E model for image generation.</li>
<li><strong>FTP Server Details</strong>: FTP server credentials (server address, username, and password) are provided for image uploads.</li>
<li><strong>Weather Details and Landscape Type</strong>: The weather description obtained earlier is stored in weather_details . A landscape type (e.g., “rural Norfolk landscape”) is specified.</li>
<li><strong>Image Prompt Creation</strong>: The image_prompt  is constructed by combining weather details and landscape type. It describes the desired image.</li>
<li><strong>Image Generation with DALL·E</strong>: The  generatrate_image function uses DALL·E to create and return an image based on the prompt.</li>
<li><strong>Datestamp Generation</strong>: A datestamp is generated for archiving purposes.</li>
<li><strong>FTP Image Upload</strong>: The upload_to_ftp function connects to the FTP server, downloads the generated image, and uploads it to specific directories &#8211; this is optional, only of use if you are hosting your images.</li>
<li><strong>Running the Script</strong>: We run the script every 12 hours, using a cron job on a Raspberry Pi. We additional send it to our iPhone and our FrameTV, so the latest image is viewable either as a widget or on screen</li>
</ol>
<p>Finally we also display it on our iPad, using the <a href="https://frame-it.framer.website/">FrameIT app</a> &#8211; this auto updates the image when a new one is uploaded to the web server.</p>
<p>&nbsp;</p>
<div id="attachment_7782" style="width: 1034px" class="wp-caption aligncenter"><img loading="lazy" decoding="async" aria-describedby="caption-attachment-7782" class="wp-image-7782 size-large" src="https://www.digitalurban.org/wp-content/uploads/2024/04/Photoroom_20240326_132608-e1714226219256-1024x732.jpg" alt="Dall-E 3 image on an iPad using Frame-IT" width="1024" height="732" srcset="https://www.digitalurban.org/wp-content/uploads/2024/04/Photoroom_20240326_132608-e1714226219256-1024x732.jpg 1024w, https://www.digitalurban.org/wp-content/uploads/2024/04/Photoroom_20240326_132608-e1714226219256-300x214.jpg 300w, https://www.digitalurban.org/wp-content/uploads/2024/04/Photoroom_20240326_132608-e1714226219256-768x549.jpg 768w, https://www.digitalurban.org/wp-content/uploads/2024/04/Photoroom_20240326_132608-e1714226219256.jpg 1280w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><p id="caption-attachment-7782" class="wp-caption-text">Dall-E 3 image on an iPad using Frame-IT</p></div>
<p>Do let us know if you create you own AI based weather images using data inputs &#8211; it would be interesting to see how different landscapes and counties compare.</p>
	</div>
</div>




			</div> 
		</div>
	</div> 
</div></div>
<p>The post <a href="https://www.digitalurban.org/blog/2024/04/27/creating-art-like-weather-forecast-images-with-dall%c2%b7e-3-and-api-data/">Creating Art Like Weather Forecast Images with DALL·E 3 and API Data</a> appeared first on <a href="https://www.digitalurban.org">Digital Urban</a>.</p>
]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Reimaging the Traditional Weather House with Open Data, Laser Cutting and 3D Printing</title>
		<link>https://www.digitalurban.org/blog/2023/08/18/reimaging-the-traditional-weather-house-with-open-data-laser-cutting-and-3d-printing/</link>
		
		<dc:creator><![CDATA[Andy]]></dc:creator>
		<pubDate>Fri, 18 Aug 2023 13:36:46 +0000</pubDate>
				<category><![CDATA[Making]]></category>
		<category><![CDATA[Weather]]></category>
		<category><![CDATA[Black Forest]]></category>
		<category><![CDATA[Open Weather Map]]></category>
		<category><![CDATA[Pi Pico]]></category>
		<category><![CDATA[Weather House]]></category>
		<guid isPermaLink="false">https://www.digitalurban.org/?p=7179</guid>

					<description><![CDATA[<p>The post <a href="https://www.digitalurban.org/blog/2023/08/18/reimaging-the-traditional-weather-house-with-open-data-laser-cutting-and-3d-printing/">Reimaging the Traditional Weather House with Open Data, Laser Cutting and 3D Printing</a> appeared first on <a href="https://www.digitalurban.org">Digital Urban</a>.</p>
]]></description>
										<content:encoded><![CDATA[
		<div id="fws_696f9d370b114"  data-column-margin="default" data-midnight="dark"  class="wpb_row vc_row-fluid vc_row"  style="padding-top: 0px; padding-bottom: 0px; "><div class="row-bg-wrap" data-bg-animation="none" data-bg-animation-delay="" data-bg-overlay="false"><div class="inner-wrap row-bg-layer" ><div class="row-bg viewport-desktop"  style=""></div></div></div><div class="row_col_wrap_12 col span_12 dark left">
	<div  class="vc_col-sm-12 wpb_column column_container vc_column_container col no-extra-padding inherit_tablet inherit_phone "  data-padding-pos="all" data-has-bg-color="false" data-bg-color="" data-bg-opacity="1" data-animation="" data-delay="0" >
		<div class="vc_column-inner" >
			<div class="wpb_wrapper">
				
<div class="wpb_text_column wpb_content_element " >
	<div class="wpb_wrapper">
		<p>Traditional German weather houses are small, decorative structures that are popular in Germany and other parts of Europe. They are often made from wood and used to predict the weather.</p>
<div class="wp-block-image">
<figure class="alignright size-large is-resized">
<div id="attachment_7297" style="width: 310px" class="wp-caption alignnone"><img loading="lazy" decoding="async" aria-describedby="caption-attachment-7297" class="wp-image-7297 size-medium" style="width: 246px; height: 159px;" src="https://www.digitalurban.org/wp-content/uploads/2023/08/Screenshot-2023-08-18-at-14.30.17-300x267.png" alt="Weather House" width="300" height="267" srcset="https://www.digitalurban.org/wp-content/uploads/2023/08/Screenshot-2023-08-18-at-14.30.17-300x267.png 300w, https://www.digitalurban.org/wp-content/uploads/2023/08/Screenshot-2023-08-18-at-14.30.17-768x684.png 768w, https://www.digitalurban.org/wp-content/uploads/2023/08/Screenshot-2023-08-18-at-14.30.17.png 788w" sizes="auto, (max-width: 300px) 100vw, 300px" /><p id="caption-attachment-7297" class="wp-caption-text">A <a href="https://www.amazon.co.uk/TFA-Dostmann-48-1503-08-Weather-House-Germany/dp/B07PHYZ5TS/ref=d_pd_sbs_sccl_4_1/262-7292782-5370661?pd_rd_w=u62wm&amp;content-id=amzn1.sym.c633ef94-5925-4800-8916-1372f3be4382&amp;pf_rd_p=c633ef94-5925-4800-8916-1372f3be4382&amp;pf_rd_r=2JMCC8RK4PJTBANJDR5M&amp;pd_rd_wg=QST5L&amp;pd_rd_r=e3c70644-02b0-416d-b212-1f06c94d20a8&amp;pd_rd_i=B07PHYZ5TS&amp;th=1">Traditional Weather House</a></p></div><br />
</figure>
</div>
<p>The way the weather house works is quite simple. Inside the house, there is a strip of catgut or hair. The gut relaxes or shrinks based on the humidity in the surrounding air, relaxing when the air is wet and tensing when the air is dry. Attached to the strip is a small figure of a man and a woman. When the humidity in the air changes, the strip will expand or contract, causing the figures to move.</p>
<p>If the weather is going to be dry and sunny, the man will come out of the house. If it is going to be wet and rainy, the woman will come out of the house. If the humidity is just right, both the man and the woman will be visible.</p>
<p>Traditional German weather houses are, an interesting, if slightly imprecise way to predict the weather. They are also a useful inspiration to develop a slightly more modern version using the Open Weather Map API, a 360-degree non-continuous servo, some neopixels and a Raspberry Pi Pico W.</p>
<p> </p>
<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="419" class="wp-image-7279" src="https://www.digitalurban.org/wp-content/uploads/2023/08/Weatherhousewide@0.5x-1024x419.jpg" alt="Weather House Laser Cut" srcset="https://www.digitalurban.org/wp-content/uploads/2023/08/Weatherhousewide@0.5x-1024x419.jpg 1024w, https://www.digitalurban.org/wp-content/uploads/2023/08/Weatherhousewide@0.5x-300x123.jpg 300w, https://www.digitalurban.org/wp-content/uploads/2023/08/Weatherhousewide@0.5x-768x314.jpg 768w, https://www.digitalurban.org/wp-content/uploads/2023/08/Weatherhousewide@0.5x-1536x628.jpg 1536w, https://www.digitalurban.org/wp-content/uploads/2023/08/Weatherhousewide@0.5x-2048x837.jpg 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">The Weather House Reimagined</figcaption></figure>
<p>In essence the house is a series of weather symbols which rotate according to the feed from the Open Weather Map API. This can be set to any location in the world and it updates every 15 minutes. It is also adaptable to change to your own source of weather data, perhaps your own personal weather station.</p>
<p> </p>
<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="614" class="wp-image-7282" src="https://www.digitalurban.org/wp-content/uploads/2023/08/WeatherHouseInternals-1024x614.jpg" alt="Weather House Components" srcset="https://www.digitalurban.org/wp-content/uploads/2023/08/WeatherHouseInternals-1024x614.jpg 1024w, https://www.digitalurban.org/wp-content/uploads/2023/08/WeatherHouseInternals-300x180.jpg 300w, https://www.digitalurban.org/wp-content/uploads/2023/08/WeatherHouseInternals-768x461.jpg 768w, https://www.digitalurban.org/wp-content/uploads/2023/08/WeatherHouseInternals-1536x921.jpg 1536w, https://www.digitalurban.org/wp-content/uploads/2023/08/WeatherHouseInternals-2048x1228.jpg 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">Weather House Components</figcaption></figure>
<p>There are also two sets of neopixels &#8211; one to light up the symbol, this works well at night and looks like an outside light on the house, allowing the weather conditions to be seen. The other is an 8 pixel neopixel strip which changes colour and animates according to the conditions. If it&#8217;s raining then the lights change to blue and simulate raindrops, for sunny spells they light and dim with tinges of yellow to simulate the sun poking out of the clouds, etc. All of these are editable in the code to change according to your own preference.</p>
<p> </p>
<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="618" class="wp-image-7284" src="https://www.digitalurban.org/wp-content/uploads/2023/08/WeatherHouseNeoPixels-1024x618.jpg" alt="Weather House Neopixels" srcset="https://www.digitalurban.org/wp-content/uploads/2023/08/WeatherHouseNeoPixels-1024x618.jpg 1024w, https://www.digitalurban.org/wp-content/uploads/2023/08/WeatherHouseNeoPixels-300x181.jpg 300w, https://www.digitalurban.org/wp-content/uploads/2023/08/WeatherHouseNeoPixels-768x463.jpg 768w, https://www.digitalurban.org/wp-content/uploads/2023/08/WeatherHouseNeoPixels-1536x927.jpg 1536w, https://www.digitalurban.org/wp-content/uploads/2023/08/WeatherHouseNeoPixels-2048x1235.jpg 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">Weather House Neopixels</figcaption></figure>
<p>At the heart of the weather house is a Raspberry Pi Pico W, held in a 3D printed enclosure which also encases the LEDs and the Servo.</p>
<p> </p>
<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="495" class="wp-image-7280" src="https://www.digitalurban.org/wp-content/uploads/2023/08/WeatherhouseTopDown-1024x495.jpg" alt="" srcset="https://www.digitalurban.org/wp-content/uploads/2023/08/WeatherhouseTopDown-1024x495.jpg 1024w, https://www.digitalurban.org/wp-content/uploads/2023/08/WeatherhouseTopDown-300x145.jpg 300w, https://www.digitalurban.org/wp-content/uploads/2023/08/WeatherhouseTopDown-768x371.jpg 768w, https://www.digitalurban.org/wp-content/uploads/2023/08/WeatherhouseTopDown-1536x743.jpg 1536w, https://www.digitalurban.org/wp-content/uploads/2023/08/WeatherhouseTopDown-2048x991.jpg 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">Weather House Laser Cut Outs</figcaption></figure>
<p>It slots into the case which, in our example, is laser cut from white perspex for the house and 3mm plywood for the roof.</p>
<p> </p>
<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="497" class="wp-image-7281" src="https://www.digitalurban.org/wp-content/uploads/2023/08/WeatherHouseLaserCut-1024x497.jpg" alt="Weather House Laser Cut Outs" srcset="https://www.digitalurban.org/wp-content/uploads/2023/08/WeatherHouseLaserCut-1024x497.jpg 1024w, https://www.digitalurban.org/wp-content/uploads/2023/08/WeatherHouseLaserCut-300x145.jpg 300w, https://www.digitalurban.org/wp-content/uploads/2023/08/WeatherHouseLaserCut-768x372.jpg 768w, https://www.digitalurban.org/wp-content/uploads/2023/08/WeatherHouseLaserCut-1536x745.jpg 1536w, https://www.digitalurban.org/wp-content/uploads/2023/08/WeatherHouseLaserCut-2048x993.jpg 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">Weather House Laser Cut Outs</figcaption></figure>
<p>Once assembled the 3D printed enclosure along with the dial, fits into the main house. The servo is set to its starting point with the &#8216;Sun&#8217; icon showing through the window.</p>
<div id="attachment_7302" style="width: 784px" class="wp-caption aligncenter"><img loading="lazy" decoding="async" aria-describedby="caption-attachment-7302" class=" wp-image-7302" src="https://www.digitalurban.org/wp-content/uploads/2023/08/Weather-House-Angled-300x166.jpg" alt="Weather House Inside View " width="774" height="428" srcset="https://www.digitalurban.org/wp-content/uploads/2023/08/Weather-House-Angled-300x166.jpg 300w, https://www.digitalurban.org/wp-content/uploads/2023/08/Weather-House-Angled-1024x567.jpg 1024w, https://www.digitalurban.org/wp-content/uploads/2023/08/Weather-House-Angled-768x425.jpg 768w, https://www.digitalurban.org/wp-content/uploads/2023/08/Weather-House-Angled-1536x851.jpg 1536w, https://www.digitalurban.org/wp-content/uploads/2023/08/Weather-House-Angled-2048x1134.jpg 2048w" sizes="auto, (max-width: 774px) 100vw, 774px" /><p id="caption-attachment-7302" class="wp-caption-text">Weather House Inside View</p></div>
<p>We power ours from a 20,000mAh power bank which keeps it running for about a week. Each time the data updates the outside lamp turns on and off, so you have a visual clue that new data has uploaded.</p>
<p> </p>
<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="508" class="wp-image-7291" src="https://www.digitalurban.org/wp-content/uploads/2023/08/Weather-House-45-Degrees-1024x508.jpg" alt="Weather House Looking Down" srcset="https://www.digitalurban.org/wp-content/uploads/2023/08/Weather-House-45-Degrees-1024x508.jpg 1024w, https://www.digitalurban.org/wp-content/uploads/2023/08/Weather-House-45-Degrees-300x149.jpg 300w, https://www.digitalurban.org/wp-content/uploads/2023/08/Weather-House-45-Degrees-768x381.jpg 768w, https://www.digitalurban.org/wp-content/uploads/2023/08/Weather-House-45-Degrees-1536x761.jpg 1536w, https://www.digitalurban.org/wp-content/uploads/2023/08/Weather-House-45-Degrees-2048x1015.jpg 2048w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">The Final Built Weather House</figcaption></figure>
	</div>
</div>




			</div> 
		</div>
	</div> 
</div></div>
		<div id="fws_696f9d370bb10"  data-column-margin="default" data-midnight="dark"  class="wpb_row vc_row-fluid vc_row"  style="padding-top: 0px; padding-bottom: 0px; "><div class="row-bg-wrap" data-bg-animation="none" data-bg-animation-delay="" data-bg-overlay="false"><div class="inner-wrap row-bg-layer" ><div class="row-bg viewport-desktop"  style=""></div></div></div><div class="row_col_wrap_12 col span_12 dark left">
	<div  class="vc_col-sm-12 wpb_column column_container vc_column_container col no-extra-padding inherit_tablet inherit_phone "  data-padding-pos="all" data-has-bg-color="false" data-bg-color="" data-bg-opacity="1" data-animation="" data-delay="0" >
		<div class="vc_column-inner" >
			<div class="wpb_wrapper">
				
<div class="wpb_text_column wpb_content_element " >
	<div class="wpb_wrapper">
		<p>The Micropython code, build components, 3D print and laser cut files are available on <a href="https://github.com/digitalurban/Weather-House">our accompanying GitHub page</a>, note the project is still a work in progress..</p>
	</div>
</div>




			</div> 
		</div>
	</div> 
</div></div><p>The post <a href="https://www.digitalurban.org/blog/2023/08/18/reimaging-the-traditional-weather-house-with-open-data-laser-cutting-and-3d-printing/">Reimaging the Traditional Weather House with Open Data, Laser Cutting and 3D Printing</a> appeared first on <a href="https://www.digitalurban.org">Digital Urban</a>.</p>
]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
