<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" 
  xmlns:dc="http://purl.org/dc/elements/1.1/" 
  xmlns:content="http://purl.org/rss/1.0/modules/content/" 
  xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>THINKING ANALOG</title>
    <link>https://thinkinganalog.com/</link>
    <description>Recent content on THINKING ANALOG</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en</language>
    <copyright>(c)2026 Martin Lanser. All rights reserved.</copyright>
    <lastBuildDate>Sat, 07 Feb 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://thinkinganalog.com/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Ex-Expat Day 180</title>
      <link>https://thinkinganalog.com/blog/ex-expat-day-180/</link>
      <pubDate>Sat, 07 Feb 2026 00:00:00 +0000</pubDate>
      
      <guid>https://thinkinganalog.com/blog/ex-expat-day-180/</guid>
      <description>
      
          
            
            
            <![CDATA[<img src="https://thinkinganalog.com/blog/ex-expat-day-180/ml-lund-grey-february-1200x800-min_hu_a3ed01182a5fbe0b.jpg" width="640" height="427"/><br>]]>
          
        
      <![CDATA[ A grey Saturday in February in Lund. Icy streets. Snow and slush. More grey. I&#39;m having some coffee and a cinnamon roll -- a Swedish power combo!]]>
      </description>
      <content:encoded>
      
          
            
            
            <![CDATA[<img src="https://thinkinganalog.com/blog/ex-expat-day-180/ml-lund-grey-february-1200x800-min_hu_a3ed01182a5fbe0b.jpg" width="640" height="427"/><br>]]>
          
        
      <![CDATA[ <p>A grey Saturday in February in <a href="https://visitlund.se/en">Lund</a>. Icy streets. Snow and slush. More grey. I&rsquo;m having some coffee and a cinnamon roll &ndash; a Swedish power combo! &ndash; at <a href="https://folkbiblioteken.lund.se/-/martas-cafe">Martas Cafe</a>, a coffee shop attached to <a href="https://folkbiblioteken.lund.se/startsida#/">Lund&rsquo;s city library</a>.</p>
<p>I really enjoy spending time at this library. In fact, I come here almost every weekend. I read the newspapers, browse some magazines, work on blog posts, and get a bit of fun coding done. And yes, it&rsquo;s nice to just sit here and ponder.</p>
<p>This is a great library. OK, here is a theory of mine: if a city has a great library, great restaurants, and coffee shops, then it&rsquo;s likely to be a great city to live in. Let me present to you some heavily subjective, totally biased, and carefully selected (and clearly anecdotal) evidence to back up the bold claim:</p>
<ul>
<li><a href="https://en.wikipedia.org/wiki/Durham,_North_Carolina">Durham, NC</a> &ndash; <a href="https://durhamcountylibrary.org/location/main-library/">great library</a>, great restaurants, and great coffee shops</li>
<li><a href="https://sv.wikipedia.org/wiki/Lund">Lund, Sweden</a> &ndash; <a href="https://folkbiblioteken.lund.se/startsida#/">great library</a>, great restaurants and bars such as <a href="https://www.matochdestillat.se">Mat &amp; Destillat</a>, and great coffee shops … well, there are probably a million in this big little city, but definitely try <a href="https://www.mannz.se/">Mannz Bageri</a> or <a href="https://patisseriet.com">Patisseriet</a></li>
</ul>
<p>Now, if we add one more parameter &ndash; walkability &ndash; then I&rsquo;d argue that Lund is likely one of the very best places to live in the world. But wait, what about sunshine and weather? Bah, who needs warm and sunny days year-round? Grey days build character!</p>
<p>And when I sit in the warm library, AirPods in my ears and music on, looking out the big windows at the grey and icy streets … then … well, whatever … I love this place! Grey and icy days and all 🥶😊</p>
]]>
      </content:encoded>
    </item>
    
    <item>
      <title>Ex-Expat Day 168</title>
      <link>https://thinkinganalog.com/blog/ex-expat-day-168/</link>
      <pubDate>Mon, 26 Jan 2026 00:00:00 +0000</pubDate>
      
      <guid>https://thinkinganalog.com/blog/ex-expat-day-168/</guid>
      <description>
      
          
            
            
            <![CDATA[<img src="https://thinkinganalog.com/blog/ex-expat-day-168/ml-copenhagen-january-morning2-1200x800-min_hu_2ed20d348b25a611.jpg" width="640" height="427"/><br>]]>
          
        
      <![CDATA[ Another early Monday morning in January. No snow yet this morning, but there’s a winter storm warning for afternoon and evening.]]>
      </description>
      <content:encoded>
      
          
            
            
            <![CDATA[<img src="https://thinkinganalog.com/blog/ex-expat-day-168/ml-copenhagen-january-morning2-1200x800-min_hu_2ed20d348b25a611.jpg" width="640" height="427"/><br>]]>
          
        
      <![CDATA[ <p>Another early Monday morning in January. No snow yet this morning, but there’s a winter storm warning for afternoon and evening. I&rsquo;m stopping in for some coffee before heading over to the office. It&rsquo;s my ease-into-Monday routine.</p>
<p>The day-job part is keeping me on my toes. There’s lots of busywork, as with any large project, and also quite a few new (at least to me) cool tools to learn. My focus is now on automated testing, which may not sound exciting. But let’s just say there are layers of complexity … lots of layers and lots of complexity and lots of machine-to-machine automation … yup, my inner nerd is smiling.</p>
<p>And yes, I’m definitely settling in, and I&rsquo;m finding my groove 😊</p>
]]>
      </content:encoded>
    </item>
    
    <item>
      <title>Ex-Expat Day 161</title>
      <link>https://thinkinganalog.com/blog/ex-expat-day-161/</link>
      <pubDate>Mon, 19 Jan 2026 00:00:00 +0000</pubDate>
      
      <guid>https://thinkinganalog.com/blog/ex-expat-day-161/</guid>
      <description>
      
          
            
            
            <![CDATA[<img src="https://thinkinganalog.com/blog/ex-expat-day-161/ml-copenhagen-january-morning-1200x800-min_hu_7139390a7880f047.jpg" width="640" height="427"/><br>]]>
          
        
      <![CDATA[ Early Monday morning in January, heading to work. I just got off the train and am walking to the office. Stopping for some coffee.]]>
      </description>
      <content:encoded>
      
          
            
            
            <![CDATA[<img src="https://thinkinganalog.com/blog/ex-expat-day-161/ml-copenhagen-january-morning-1200x800-min_hu_7139390a7880f047.jpg" width="640" height="427"/><br>]]>
          
        
      <![CDATA[ <p>Early Monday morning in January, heading to work. I just got off the train and am walking to the office. Stopping for some coffee.</p>
<p>It&rsquo;s still early. A few minutes to ponder life. Actually, it&rsquo;s not that serious. But it&rsquo;s nice to just &lsquo;be&rsquo; for a few minutes. Soon I&rsquo;ll be neck-deep in schedules and planning and slide decks and status reports and Teams calls and Slack messages and emails.</p>
<p>I know I&rsquo;m late to the party, but perhaps I should come up with some resolutions for the new year. It&rsquo;s still early January … so why not give it a shot?</p>
<p>How about:
… seriously planning to slow down? Well, that may have to wait until December. But next year will definitely have to be slower!</p>
<p>… spend more time with the whole family in general? Yes. That we&rsquo;ll do. After all, most of us are now in the same time zone and even in the same country 😊</p>
<p>… read and write more … uhm … that one is on the list every year. But this year is different! This year I will find time … of course, I say that every year. I guess we&rsquo;ll see. I do have two new (not so secret) weapons: the city library and the university library … and I love sitting there … so maybe this is the year after all 🤓</p>
]]>
      </content:encoded>
    </item>
    
    <item>
      <title>Ex-Expat Day 151</title>
      <link>https://thinkinganalog.com/blog/ex-expat-day-151/</link>
      <pubDate>Fri, 09 Jan 2026 00:00:00 +0000</pubDate>
      
      <guid>https://thinkinganalog.com/blog/ex-expat-day-151/</guid>
      <description>
      
          
            
            
            <![CDATA[<img src="https://thinkinganalog.com/blog/ex-expat-day-151/ml-empty-seats-1200x800-min_hu_b1d5ef9f3f54693c.jpg" width="640" height="427"/><br>]]>
          
        
      <![CDATA[ Traveling in style today back from a few days of meetings in Antwerp. I have the whole last row on this morning’s Brussels Air flight all to myself.]]>
      </description>
      <content:encoded>
      
          
            
            
            <![CDATA[<img src="https://thinkinganalog.com/blog/ex-expat-day-151/ml-empty-seats-1200x800-min_hu_b1d5ef9f3f54693c.jpg" width="640" height="427"/><br>]]>
          
        
      <![CDATA[ <p>Traveling in style today back from a few days of meetings in <a href="https://en.wikipedia.org/wiki/Antwerp">Antwerp</a>. I have the whole last row on this morning’s Brussels Air flight all to myself. Sure, there are no windows, the seats do not recline, and it’s quite tight when I try to sit upright. But hey, an empty row right by the toilet … can it get much more luxurious?</p>
<p>Anyway, it’s a short flight, and I’ll be home soon. I wish I could go by train. Of course, it’s technically possible but quite impractical to do so from Copenhagen. There are no direct trains, so one would have to switch trains at least 3 or 4 times, and total travel time is up around 12 hours or so. It’s a bit difficult to justify a train ride if it’s longer than 6 hours and the comparable door-to-door time for a flight is around 5 hours.</p>
<p>But travel by train would definitely be more fun. 🚄</p>
]]>
      </content:encoded>
    </item>
    
    <item>
      <title>December 2025</title>
      <link>https://thinkinganalog.com/notes/december-2025/</link>
      <pubDate>Wed, 31 Dec 2025 00:00:00 +0000</pubDate>
      
      <guid>https://thinkinganalog.com/notes/december-2025/</guid>
      <description>
      
          
            
            
            <![CDATA[<img src="https://thinkinganalog.com/notes/december-2025/pexels-woki-nguyn-736232093-18738369-1200x800-min_hu_4a7ab0761dbe8a60.jpg" width="640" height="427"/><br>]]>
          
        
      <![CDATA[ Another year is coming to a close. But this was not just any year -- no, this year turned out to be an insane year and a total reboot!]]>
      </description>
      <content:encoded>
      
          
            
            
            <![CDATA[<img src="https://thinkinganalog.com/notes/december-2025/pexels-woki-nguyn-736232093-18738369-1200x800-min_hu_4a7ab0761dbe8a60.jpg" width="640" height="427"/><br>]]>
          
        
      <![CDATA[ <p>Another year is coming to a close. But this is not just any year &ndash; no, this year turned out to be a total reboot! It started like any other year &hellip; actually, no, it did not. It started with the younger child going to Sweden for an exchange semester and my going there to celebrate her birthday. Sweden in January is an acquired taste.</p>
<p>Then another trip to <a href="https://en.wikipedia.org/wiki/Copenhagen">Copenhagen</a> and <a href="https://en.wikipedia.org/wiki/Lund">Lund</a> at the end of May, when we also took the opportunity to look at some apartments in Lund. We love this town! It&rsquo;s small, but it punches well above its weight. And with the proximity to <a href="https://en.wikipedia.org/wiki/Malm%C3%B6">Malmö</a> and, more importantly, Copenhagen, this is the perfect corner of Europe.</p>
<p>The decision was made to get everything ready for a move back to Europe. Now it was time to plan and to outline the when, what, and how. An orderly exit after over three decades in the States back to Europe.</p>
<p>Then, a series of events and a huge opportunity. Previous timelines were scrapped, and a new accelerated plan was put in motion. A one-way ticket back to Europe for mid-August was purchased, capping off a 35-year adventure.</p>
<p>Now I live in Sweden again, and things sure are totally different. Sweden today is completely digital; almost every action or interaction is done on mobile phones. Now, when I left Sweden, there was no internet and there were no mobile phones. So yes, life here is now very different.</p>
<p>And to make things a bit more complicated, I work at a startup in Copenhagen. For one, that means commuting to a different country. Then there&rsquo;s the switch from working at a huge bank in the States to working at a startup again. Oh, then there&rsquo;s the thing of dealing with multiple currencies &ndash; Swedish kronor, Danish kronor, U.S. dollars, and the euro. Then there&rsquo;s going back to the metric system, the 24-hour clock, and the different date format, which is still messing me up &hellip; so for now I&rsquo;m spelling out the month name to be on the safe side. 🤓</p>
<p>Then there&rsquo;s the not-owning-a-car thing and walking everywhere or using public transportation. And yes, I actually like that part. It&rsquo;s actually nice to not sit in traffic all the time and to not have to drive everywhere all the time.</p>
<p>Then there&rsquo;s the whole quality-of-life thing. Sure, I work quite a lot. But somehow it feels different. Somehow I feel a lot less stressed. In fact, I don&rsquo;t feel stressed. Sure, there are minor frustrations here and there from time to time. But that&rsquo;s just life.</p>
<p>Overall, though, I don&rsquo;t feel stressed. Maybe it&rsquo;s just that I&rsquo;m just older and simply care less. But life here is much more relaxed. There&rsquo;s less chasing and being chased, and a lot more being.</p>
<p>What an insane year!</p>
]]>
      </content:encoded>
    </item>
    
    <item>
      <title>Ex-Expat Day 141</title>
      <link>https://thinkinganalog.com/blog/ex-expat-day-141/</link>
      <pubDate>Tue, 30 Dec 2025 00:00:00 +0000</pubDate>
      
      <guid>https://thinkinganalog.com/blog/ex-expat-day-141/</guid>
      <description>
      
          
            
            
            <![CDATA[<img src="https://thinkinganalog.com/blog/ex-expat-day-141/pexels-vishnu-panday-94089132-31106210-1200x800-min_hu_8bd1355f2d54091b.jpg" width="640" height="427"/><br>]]>
          
        
      <![CDATA[ Sitting at a coffee shop in Copenhagen before walking into the office. Outside it&#39;s a dark, wet, and cold Tuesday morning.]]>
      </description>
      <content:encoded>
      
          
            
            
            <![CDATA[<img src="https://thinkinganalog.com/blog/ex-expat-day-141/pexels-vishnu-panday-94089132-31106210-1200x800-min_hu_8bd1355f2d54091b.jpg" width="640" height="427"/><br>]]>
          
        
      <![CDATA[ <p>Sitting at a coffee shop in Copenhagen before walking into the office. It&rsquo;s still very early in the morning. Only a few places are open.</p>
<p>Outside it&rsquo;s a dark, wet, and cold Tuesday morning… but not freezing or icy… yet. Most Christmas decorations are gone. It&rsquo;s so dark. Gloomy, actually. Later it will go from dark to dark grey… it&rsquo;s that kind of day.</p>
<p>There are a few more people on their way to some place. Work, probably. Walking. Bicycling. People here ride their bikes year-round and in every type of weather. Rain, snow, ice, sleet… it doesn&rsquo;t matter.</p>
<p>It&rsquo;s the last few working days of 2025, and I still have a lot of work to do. I want to hit the ground running the 1st full week of January when everyone else is back from their winter holidays.</p>
<p>But first, a warm cup of coffee. I need a few minutes of peace and quiet. ☕️</p>
]]>
      </content:encoded>
    </item>
    
    <item>
      <title>Ex-Expat Day 101</title>
      <link>https://thinkinganalog.com/blog/ex-expat-day-101/</link>
      <pubDate>Thu, 20 Nov 2025 00:00:00 +0000</pubDate>
      
      <guid>https://thinkinganalog.com/blog/ex-expat-day-101/</guid>
      <description>
      
          
            
            
            <![CDATA[<img src="https://thinkinganalog.com/blog/ex-expat-day-101/lund-c-snowing-1200x800-min_hu_c513fb006f2e762f.jpg" width="640" height="427"/><br>]]>
          
        
      <![CDATA[ It’s snowing! First snow of the season. It’s cold and dark. The days are short. Very short.]]>
      </description>
      <content:encoded>
      
          
            
            
            <![CDATA[<img src="https://thinkinganalog.com/blog/ex-expat-day-101/lund-c-snowing-1200x800-min_hu_c513fb006f2e762f.jpg" width="640" height="427"/><br>]]>
          
        
      <![CDATA[ <p>It’s snowing! First snow of the season. It’s cold and dark. The days are short. Very short.</p>
<p>It will definitely take some time getting used to this. It’s still dark when I leave for work in the morning and already dark when I get home in the evening.</p>
<p>I moved to Sweden just over 3 months ago, and a lot has changed. Actually, everything has changed… profoundly! And I have changed.</p>
<p>I used to be a Swedish American. But now I’m an American Swede… and apparently with an American accent. I guess that’s what happens after 35 years in the States.</p>
<p>Interesting side note: I just got back from a few days in the States, and one thing that struck me was how much time I spent driving from place to place. And this was just running errands and doing normal day-to-day things.</p>
<p>I bet I spent on average well over an hour, if not more, per day just driving from place to place. And this was not commuting to work—just doing regular things.</p>
<p>I don’t drive anywhere in my new life. Instead, I walk to most places or take the train. Sure, I spend about 2 1/2 hours commuting most weekdays. However, I doubt that total time in transit per week is much more than all that time driving in the States.</p>
<p>More importantly, I like not spending all that time driving, and I really like being able to walk to most places.</p>
<p>So, just over 100 days in, and I’m already so much more European. 😊</p>
]]>
      </content:encoded>
    </item>
    
    <item>
      <title>Ex-Expat Day 17</title>
      <link>https://thinkinganalog.com/blog/ex-expat-day-17/</link>
      <pubDate>Thu, 28 Aug 2025 00:00:00 +0000</pubDate>
      
      <guid>https://thinkinganalog.com/blog/ex-expat-day-17/</guid>
      <description>
      
          
            
            
            <![CDATA[<img src="https://thinkinganalog.com/blog/ex-expat-day-17/stockholm-4b-1200x800-min_hu_5c6b334551682b42.jpg" width="640" height="427"/><br>]]>
          
        
      <![CDATA[ It&#39;s a strange feeling to sit in these coffee shops in the morning, watching people get their coffee, pastry, sandwich, tea, or whatever. Some stay. Some take their order to go. Some sit and read. Some are in a hurry.]]>
      </description>
      <content:encoded>
      
          
            
            
            <![CDATA[<img src="https://thinkinganalog.com/blog/ex-expat-day-17/stockholm-4b-1200x800-min_hu_5c6b334551682b42.jpg" width="640" height="427"/><br>]]>
          
        
      <![CDATA[ <p>It&rsquo;s a strange feeling to sit in these coffee shops in the morning, watching people get their coffee, pastry, sandwich, tea, or whatever. Some stay. Some take their order to go. Some sit and read. Some are in a hurry. Some meet up with friends or colleagues. Some are by themselves.</p>
<p>I have nothing to do and no particular place to be. I&rsquo;m killing time one cup of coffee at a time. I&rsquo;m not on vacation, but I&rsquo;m also not working. I&rsquo;m in this weird transition period &ldquo;between jobs&rdquo; &hellip; or at least I hope I am. A few weeks ago, I lived on a different continent and in a different world. Now I&rsquo;m starting over &hellip; again &hellip; in a different country.</p>
<p>My life right now can be characterized mainly as &ldquo;hurry up and wait&rdquo; &hellip; lots of waiting for all kinds of things. It&rsquo;s a strange place, this &ldquo;in between&rdquo; &hellip; in between jobs, in between homes, in between lives. Everything is &ldquo;in progress,&rdquo; but nothing is ready. Everything is temporary, and everything can change by tomorrow, or next week, or next month.</p>
<p>In fact, many things will have changed by next month. But which things? When? In what order? How?</p>
<p>So for now, another cup of coffee. Killing some more time. Waiting. ☕️</p>
]]>
      </content:encoded>
    </item>
    
    <item>
      <title>Ex-Expat Day 16</title>
      <link>https://thinkinganalog.com/blog/ex-expat-day-16/</link>
      <pubDate>Wed, 27 Aug 2025 00:00:00 +0000</pubDate>
      
      <guid>https://thinkinganalog.com/blog/ex-expat-day-16/</guid>
      <description>
      
          
            
            
            <![CDATA[<img src="https://thinkinganalog.com/blog/ex-expat-day-16/stockholm-3-1200x800-min_hu_4c0600f7b61f551b.jpg" width="640" height="427"/><br>]]>
          
        
      <![CDATA[ Another morning in Stockholm. Another coffee shop. Another day of re-familiarizing myself with life in Sweden.]]>
      </description>
      <content:encoded>
      
          
            
            
            <![CDATA[<img src="https://thinkinganalog.com/blog/ex-expat-day-16/stockholm-3-1200x800-min_hu_4c0600f7b61f551b.jpg" width="640" height="427"/><br>]]>
          
        
      <![CDATA[ <p>Another morning in Stockholm. Another coffee shop. Another day of re-familiarizing myself with life in Sweden. And yes, another day of criss-crossing the city by tram, subway, and bus &hellip; and on foot! I gotta get my steps in, right?</p>
<p>I&rsquo;m both a tourist and a native. I recognize some places, and am totally lost in others. Familiar places. New places. Wrong subway platform. Right exit to that one street.</p>
<p>So many bridges. I forgot that Stockholm is made up of an infinite number of islands. Beautiful parks. Old buildings. New buildings. So many coffee shops. How much coffee do Swedes drink?</p>
<p>Water. Bridges. Boats. Everywhere. This is a great city! 😊</p>
]]>
      </content:encoded>
    </item>
    
    <item>
      <title>Ex-Expat Day 12</title>
      <link>https://thinkinganalog.com/blog/ex-expat-day-12/</link>
      <pubDate>Sat, 23 Aug 2025 00:00:00 +0000</pubDate>
      
      <guid>https://thinkinganalog.com/blog/ex-expat-day-12/</guid>
      <description>
      
          
            
            
            <![CDATA[<img src="https://thinkinganalog.com/blog/ex-expat-day-12/stockholm-2-1200x800-min_hu_9d8f67ce7074ae78.jpg" width="640" height="427"/><br>]]>
          
        
      <![CDATA[ It&#39;s been almost 2 weeks now since I completely rebooted my life. I&#39;m on a different continent and in a different country, some 6 time zones to the east. Different language. Different culture. Different weather. Different everything.]]>
      </description>
      <content:encoded>
      
          
            
            
            <![CDATA[<img src="https://thinkinganalog.com/blog/ex-expat-day-12/stockholm-2-1200x800-min_hu_9d8f67ce7074ae78.jpg" width="640" height="427"/><br>]]>
          
        
      <![CDATA[ <p>It&rsquo;s been almost 2 weeks now since I completely rebooted my life. Yes, rebooted—that&rsquo;s how it feels. Virtually every aspect of my life has been reset. I&rsquo;m on a different continent and in a different country, some 6 time zones to the east. Different language. Different culture. Different weather. Different everything.</p>
<p>Sure, I grew up here. But now, some 35 years later, everything is very different. Familiar, yes. But still very different. So many things have changed. So many things are new. I don&rsquo;t feel like a foreigner, but I also do not feel like a native. I don&rsquo;t blend in, but I&rsquo;m also not out of place.</p>
<p>Things are moving relatively quickly. Two weeks in, and I&rsquo;ve been able to resolve or at least initiate a few essential aspects of life in modern Sweden. Mobile phone, bank account, and, most importantly, a bank ID. Life in modern Sweden is almost entirely digital, and it&rsquo;s quite challenging to function without those three things. Worse, they go hand in hand.</p>
<p>So I&rsquo;m slowly clearing one hurdle after another, and while there are still a few more to go, I can feel the progress. Now I have to wait &hellip; patiently. Some things simply take time. However, patience is not (yet?) one of my superpowers. I&rsquo;ll have to work on that.</p>
<p>Overall, the process of moving here has been fairly smooth, and I&rsquo;m excited about this new phase in my life. And no, I have no idea how anything will turn out or even what will happen next. In fact, I don&rsquo;t even know what will happen next week. Maybe nothing. Perhaps something important. Who knows?</p>
<p>One thing is certain: this has been one hell of a ride so far 😉</p>
]]>
      </content:encoded>
    </item>
    
    <item>
      <title>Ex-Expat Day 1</title>
      <link>https://thinkinganalog.com/blog/ex-expat-day-1/</link>
      <pubDate>Tue, 12 Aug 2025 00:00:00 +0000</pubDate>
      
      <guid>https://thinkinganalog.com/blog/ex-expat-day-1/</guid>
      <description>
      
          
            
            
            <![CDATA[<img src="https://thinkinganalog.com/blog/ex-expat-day-1/stockholm-1-1200x800-min_hu_36cb8d395b1d0e37.jpg" width="640" height="427"/><br>]]>
          
        
      <![CDATA[ Well, it&#39;s day one as an ex-expat back in Sweden after 35 years in the States. I grew up here, but I&#39;ve been away for so long that I have to refamiliarize myself with pretty much all aspects of life in Sweden.]]>
      </description>
      <content:encoded>
      
          
            
            
            <![CDATA[<img src="https://thinkinganalog.com/blog/ex-expat-day-1/stockholm-1-1200x800-min_hu_36cb8d395b1d0e37.jpg" width="640" height="427"/><br>]]>
          
        
      <![CDATA[ <p>So … where to begin? Well, it&rsquo;s day one as an ex-expat back in Sweden after 35 years in the States. I grew up here, but I&rsquo;ve been away for so long that I have to refamiliarize myself with pretty much all aspects of life in Sweden.</p>
<p>Sure, I&rsquo;m obviously fluent in Swedish, albeit with an American twang, apparently. But even the language has changed. There are so many more English words that have been adopted and adapted.</p>
<p>Life in modern Sweden is almost completely digital. Literally everything is online, and almost all services are accessible on your phone. Of course, the flipside is that you cannot really function without a mobile phone (with a Swedish phone number!) or a digital ID. That then leads to some interesting Catch-22 situations.</p>
<p>For example, to get a regular phone plan, you need a so-called Bank ID, for which you need a bank account, which requires a physical address, which requires a bank account and a Bank ID. Yes, there are ways around this. There&rsquo;s something called a Freja ID, and you can get prepaid phone plans. But, not having a Bank ID signals that you don&rsquo;t have a bank account which means you&rsquo;re less likely to get access to other things and on and on. Oh, and forget cash.</p>
<p>As with so many societies, once you&rsquo;re &ldquo;in,&rdquo; things work fairly smoothly. It&rsquo;s getting &ldquo;in&rdquo; that can be very frustrating. I&rsquo;m lucky that I have family here, and things are a lot easier. I have to admit, though, it&rsquo;s interesting to observe this modern society as an outsider again. And when you ask a Swede to explain how to do things or which rules apply to this or that, you can get them to realize how circular certain aspects of life in Sweden are.</p>
<p>Now, there&rsquo;s one more thing that at least for a while, will throw me for a loop: I think in English, but I obviously speak Swedish when I talk to Swedes. This then sometimes results in my speaking Swedish with American sentence structure and wording. But it also messes with my English. Fun times! 😉</p>
]]>
      </content:encoded>
    </item>
    
    <item>
      <title>Social ME-dia III</title>
      <link>https://thinkinganalog.com/blog/social-me-dia-3/</link>
      <pubDate>Sat, 10 Feb 2024 00:00:00 +0000</pubDate>
      
      <guid>https://thinkinganalog.com/blog/social-me-dia-3/</guid>
      <description>
      
          
            
            
            <![CDATA[<img src="https://thinkinganalog.com/blog/social-me-dia-3/pexels-pixabay-163064-1200x800-min_hu_10bd866620de8d15.jpg" width="640" height="427"/><br>]]>
          
        
      <![CDATA[ I&#39;m enjoying my experience in the fediverse andI feel that I &#34;found my tribe.&#34; But I&#39;m also continuing my efforts to improve my social media diet and reduce my overall digital footprint.]]>
      </description>
      <content:encoded>
      
          
            
            
            <![CDATA[<img src="https://thinkinganalog.com/blog/social-me-dia-3/pexels-pixabay-163064-1200x800-min_hu_10bd866620de8d15.jpg" width="640" height="427"/><br>]]>
          
        
      <![CDATA[ <p>Some time ago,  I decided to delete my <a href="https://facebook.com">Facebook</a> and <a href="https://twitter.com">Twitter</a> accounts. I also removed the <a href="https://instagram.com">Instagram</a> app from my phone, and my social media presence is now (more or less) limited to <a href="https://fosstodon.org/@mlanser">Mastodon</a>.</p>
<p>Why? One (long) word: <a href="https://en.wikipedia.org/wiki/Enshittification#:~:text=Enshittification%2C%20also%20known%20as%20platform,Reddit%2C%20Twitter%2C%20and%20Unity.">enshittification</a>! I simply don&rsquo;t like being on those other platforms.</p>
<p>Conversely, I feel that I &ldquo;found my tribe&rdquo; on Mastodon. There are so many interesting people there posting tons of interesting stuff. I&rsquo;m also spending a bit more time on a few select Reddit forums and am keeping half an eye on <a href="https://linkedin.com">LinkedIn</a>, mainly for work-related things.</p>
<p>I deleted my <a href="https://medium.com">Medium</a> account but kept my <a href="https://youtube.com">Youtube</a> and (locked down) Instagram account (for now). And, occasionally, I may be lurking on <a href="https://threads.net">Threads</a> when bored out of my mind and stuck on some mindless call. Guilty pleasures, for sure, and only consumed using browsers. I also had to get a new Facebook account as our HOA and neighborhood organization only post updates there. But again, I have no apps on my phone or tablet and only visit the site as needed.</p>
<p>For Mastodon, though, I have installed the excellent <a href="https://apps.apple.com/us/app/ice-cubes-for-mastodon/id6444915884">&ldquo;Ice Cubes&rdquo; app</a> on both phone and tablet. On my laptop, I use the browser and access the Mastodon web app, which is pretty good and more than enough for my needs.</p>
<p>In short, I&rsquo;m still very pleased with my move to the <a href="https://en.wikipedia.org/wiki/Fediverse#Fediverse_software_platforms">fediverse</a>, and I definitely do not miss Twitter or Facebook. I may also delete my <a href="https://pinterest.com">Pinterest</a> and <a href="https://tumblr.com">Tumblr</a> accounts shortly and further reduce my digital footprint. And no, I will not get accounts on <a href="https://bsky.social/">Bluesky</a> or <a href="https://www.tiktok.com/">TikTok</a> either.</p>
]]>
      </content:encoded>
    </item>
    
    <item>
      <title>January 2024</title>
      <link>https://thinkinganalog.com/notes/january-2024/</link>
      <pubDate>Wed, 31 Jan 2024 00:00:00 +0000</pubDate>
      
      <guid>https://thinkinganalog.com/notes/january-2024/</guid>
      <description>
      
          
            
            
            <![CDATA[<img src="https://thinkinganalog.com/notes/january-2024/pexels-david-kanigan-15274575-1200x800-min_hu_13e67bfdd98e95bb.jpg" width="640" height="427"/><br>]]>
          
        
      <![CDATA[ January — it&#39;s a new year (already) filled with infinite meetings. Weekends in coffee shops and galleries and finding interesting antiques in old warehouses.]]>
      </description>
      <content:encoded>
      
          
            
            
            <![CDATA[<img src="https://thinkinganalog.com/notes/january-2024/pexels-david-kanigan-15274575-1200x800-min_hu_13e67bfdd98e95bb.jpg" width="640" height="427"/><br>]]>
          
        
      <![CDATA[ <p>A new year. A longer year &hellip; it&rsquo;s a leap year! We are back to work, and the meetings are filling the calendar. They are trickling in like water from a leaky faucet. Filling every nook and cranny of a work schedule. When are we supposed to get work done? But the weekends are free to spend in coffee shops pondering life&rsquo;s mysteries. Or sitting at home reading, or writing, or doing whatever.</p>
<p>Here goes January:</p>
<ul>
<li><strong>Meetings &hellip; so many meetings</strong> — I seriously think there&rsquo;s a gremlin in my Outlook calendar that sneaks in new meetings when I look away 😏</li>
<li><strong>Coffee shops</strong> — going to coffee shops with daughter and making sure to eat pastries to properly balance out any possible progress towards a healthy living I may make when I go to the gym a million times per week. Yes, I know it&rsquo;s self-defeating &hellip; but I like pastries with my coffee.</li>
<li><strong>Teenager is no longer teenager</strong> — one realizes how one is when one&rsquo;s children are suddenly all grown up. I&rsquo;m old!</li>
<li><strong>Antiques and weird old stuff</strong> — free weekends also mean rummaging through &ldquo;antiques&rdquo; in warehouses and stores. And no, not everything is a &ldquo;diamond in the rough&rdquo; &hellip; sometimes junk is just that, junk 😑</li>
</ul>
<p>Short version: January — it&rsquo;s a new year (already) filled with infinite meetings. Weekends in coffee shops and galleries and finding interesting antiques in old warehouses.</p>
]]>
      </content:encoded>
    </item>
    
    <item>
      <title>f451 Labs RPI EnviroMon Application</title>
      <link>https://thinkinganalog.com/projects/f451-labs-rpi-enviromon-app/</link>
      <pubDate>Mon, 01 Jan 2024 00:00:00 +0000</pubDate>
      
      <guid>https://thinkinganalog.com/projects/f451-labs-rpi-enviromon-app/</guid>
      <description>
      
          
            
            
            <![CDATA[<img src="https://thinkinganalog.com/projects/f451-labs-rpi-enviromon-app/f451-labs-enviromon-cli-1200x800-min_hu_e4f8f58b6f41f3e6.jpg" width="640" height="427"/><br>]]>
          
        
      <![CDATA[ The *f451 Labs EnviroMon* application is designed to run RPIs which are equipped with a Sense HAT add-ons. The main objective is to continously read environment data and upload the data to a cloud service.]]>
      </description>
      <content:encoded>
      
          
            
            
            <![CDATA[<img src="https://thinkinganalog.com/projects/f451-labs-rpi-enviromon-app/f451-labs-enviromon-cli-1200x800-min_hu_e4f8f58b6f41f3e6.jpg" width="640" height="427"/><br>]]>
          
        
      <![CDATA[ 

<div class="notices note" ><p>This application is running on my <a href="https://thinkinganalog.com/projects/f451-labs-pienviro"><em>f451 Labs piENVIRO</em> device</a>.</p></div>

<h2 id="overview">Overview</h2>
<p>This application is designed for my <a href="https://thinkinganalog.com/projects/f451-labs-pienviro"><em>f451 Labs piENVIRO</em></a> device, which is equipped with a <a href="https://shop.pimoroni.com/products/enviro?variant=31155658457171">Pimoroni Enviro+ HAT</a> add-on. The main objective is to continuously read environment data (e.g. temperature, barometric pressure, and humidity) from the Enviro+ sensors and then upload the data to the <a href="https://io.adafruit.com">Adafruit IO service</a>.</p>
<h2 id="install">Install</h2>
<p>This application is not available on PyPi. However, you can still use <code>pip</code> to install the module directly from GitHub (see below).</p>
<h3 id="dependencies">Dependencies</h3>
<p>This module is dependent on the following libraries:</p>
<ul>
<li><a href="https://github.com/pimoroni/enviroplus-python/">enviroplus-python</a> — only install if you have a physical Enviro+ device</li>
<li><a href="https://pypi.org/project/adafruit-io/">adafruit-io</a> — only install if you have an account with the Adafruit IO service</li>
</ul>
<p>NOTE: You can run this app in demo mode on (almost) any device, even without the Enviro+. It will then create random numbers and can send output to the <code>logger</code> when log level is <code>DEBUG</code> or when <code>--debug</code> flag is used.</p>
<h3 id="installing-from-github-using-pip">Installing from GitHub using <code>pip</code></h3>
<p>You can use <code>pip install</code> to install this module directly from GitHub as follows:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>$ pip install <span style="color:#e6db74">&#39;f451-piENVIRO @ git+https://github.com/mlanser/f451-piENVIRO.git&#39;</span>
</span></span></code></pre></div><h3 id="whats-with-the-name-f451-pienviro">What&rsquo;s with the name &lsquo;<em>f451-piENVIRO</em>&rsquo;</h3>
<p>The original idea behind this repo was to hold all applications running on a particular Raspberry Pi device — <a href="https://thinkinganalog.com/projects/f451-labs-pienviro">piENVIRO</a> — in my network. This device has a specific hardware configuration and general &ldquo;purpose&rdquo; (i.e. to read and process environment data).</p>
<p>So, if/when I add more applications to this device, they&rsquo;ll also be added to this repo and show up as &lsquo;scripts&rsquo; entry points in the <code>pyprojects.toml</code> file.</p>
<h2 id="how-to-use">How to use</h2>
<h3 id="running-the-application">Running the application</h3>
<p>The <code>enviromon</code> application is designed to run unsupervised, and it will collect and upload data until it is interrupted by some external event (e.g. keyboard interrupt, process <code>kill</code> command, etc.)</p>
<p>To launch this application from a terminal:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>$ nohup python -u enviromon.py &gt; enviromon.out &amp;
</span></span></code></pre></div><p>This command launches the <code>enviromon</code> application in the background. The application will keep running even after the terminal window is closed. Any output will be redirected to the <code>enviromon.out</code> file.</p>
<p>It&rsquo;s also possible to install this application via <code>pip</code> from GitHub, and one can then launch the application as follows:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>$ nohup enviromon &gt; enviromon.out &amp;
</span></span></code></pre></div><h3 id="interacting-with-the-application">Interacting with the application</h3>
<p>The <code>enviromon</code> application can read settings from both a <code>settings.toml</code> file and from CLI arguments:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># Use CLI arg &#39;-h&#39; to see available options</span>
</span></span><span style="display:flex;"><span>$ enviromon -h 
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Stop after 10 uploads</span>
</span></span><span style="display:flex;"><span>$ enviromon --uploads <span style="color:#ae81ff">10</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Show &#39;progress bar&#39; regardless of setting in &#39;toml&#39; file</span>
</span></span><span style="display:flex;"><span>$ enviromon --progress
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Show specific display mode (e.g. &#39;temperature&#39;) regardless </span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># of setting in &#39;toml&#39; file</span>
</span></span><span style="display:flex;"><span>$ enviromon --dmode temperature
</span></span></code></pre></div><p>The format of the <code>settings.toml</code> file is straightforward, and this is also where you should store Adafruit IO credentials. The <code>settings.toml</code> file only supports numbers and strings. But you define most aspects of the applications here.</p>
<p>For example, if you change the <code>PROGRESS</code> setting to 1, then the Enviro+ LCD will display a progress bar indicating when the next (simulated) upload will happen.</p>
<p>There is a &lsquo;sleep mode&rsquo; which turns off the display automatically after a certain amount of time. But you can also turn on/off the LED display by pushing/tapping the joystick button (down).</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-toml" data-lang="toml"><span style="display:flex;"><span><span style="color:#75715e"># File: settings.toml</span>
</span></span><span style="display:flex;"><span>...
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">PROGRESS</span> = <span style="color:#ae81ff">1</span>    <span style="color:#75715e"># [0|1] - 1 = show upload progress bar on LED</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">SLEEP</span> = <span style="color:#ae81ff">600</span>     <span style="color:#75715e"># Delay in seconds until screen is blanked</span>
</span></span><span style="display:flex;"><span>...
</span></span></code></pre></div><p>Please refer to the section &ldquo;<em>Custom application settings in SETTINGS.TOML</em>&rdquo; below for more information on available options in the <code>settings.toml</code> file.</p>
<p>The <code>enviromon</code> application can display live data in the terminal and on the Enviro+ LCD. If you do not want to see any output in the terminal (e.g. if you want to run the application in the background), then you can start the application with the <code>--noCLI</code> flag. Similarly, the <code>--noLED</code> flag prevents any output to the Enviro+ LCD.</p>
<p>This application offers 5 different display modes for the Enviro+ LCD:</p>
<ul>
<li><em>temperature</em> — show realtime graph of current temperature data</li>
<li><em>pressure</em> — show realtime graph of current baromteric pressure data</li>
<li><em>humidity</em> — show realtime graph of current humidity data</li>
<li><em>all</em> — show latests data points as text in dual columns</li>
<li><em>sparkles</em> — show random pixels light up — looks great at night and lets you know the app is running 😉</li>
</ul>
<p>You can switch between display modes by covering the Enviro+ light sensor for a fraction of a second. We&rsquo;re using the proximity data to trigger a switch, and you can switch through all display modes.</p>
<p>Finally, you can exit the application using the <code>ctrl-c</code> command. If you use the <code>--uploads N</code> command line argument, the application will stop after <em>N</em> (simulated) uploads.</p>
<h2 id="how-to-test">How to test</h2>


<div class="notices info" ><p>This test suite is still very much WIP.</p></div>

<p>The tests are written for <a href="https://docs.pytest.org/en/7.1.x/contents.html">pytest</a> and we use markers to separate out tests that require the actual Enviro+ hardware. Some tests do not rely on the hardware to be present. However, those tests rely on the <code>pytest-mock</code> module to be present.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># Run all tests (except marked &#39;skip&#39;)</span>
</span></span><span style="display:flex;"><span>$ pytest
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Run tests with &#39;hardware&#39; marker</span>
</span></span><span style="display:flex;"><span>$ pytest -m <span style="color:#e6db74">&#34;hardware&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Run tests without &#39;hardware&#39; marker</span>
</span></span><span style="display:flex;"><span>$ pytest -m <span style="color:#e6db74">&#34;not hardware&#34;</span>
</span></span></code></pre></div><h2 id="custom-application-settings-in-settingstoml">Custom application settings in SETTINGS.TOML</h2>
<p>The &lsquo;settings.toml&rsquo; file holds various custom application settings and secrets (e.g. Adafruit IO keys, etc.) and this file should <strong>NOT</strong> be included in &lsquo;git&rsquo; commits.</p>
<p>It is recommended to copy the &lsquo;<em>settings.example</em>&rsquo; to &lsquo;<em>settings.toml</em>&rsquo; and then customize the values in &lsquo;<em>settings.toml</em>&rsquo; as needed for the specific device that the application is running on.</p>
<h3 id="adafruit-io-settings">Adafruit IO settings</h3>
<ul>
<li>
<p><strong>AIO_USERNAME</strong>: &lsquo;string&rsquo; - Adafruit IO username</p>
</li>
<li>
<p><strong>AIO_KEY</strong>: &lsquo;string&rsquo; - Adafruit IO key</p>
</li>
<li>
<p><strong>AIO_UPLOAD</strong>: &lsquo;string&rsquo; - yes | force | no</p>
<ul>
<li>&ldquo;yes&rdquo; - <em>upload if feed available</em></li>
<li>&ldquo;force&rdquo; - <em>exit if feed invalid</em></li>
<li>&ldquo;no&rdquo; - <em>do not upload data</em></li>
</ul>
</li>
<li>
<p><strong>FEED_TEMPS</strong>: &lsquo;string&rsquo; - Adafruit IO feed key for &rsquo;temperature&rsquo; feed</p>
</li>
<li>
<p><strong>FEED_PRESS</strong>: &lsquo;string&rsquo; - Adafruit IO feed key for &lsquo;pressure&rsquo; feed</p>
</li>
<li>
<p><strong>FEED_HUMID</strong>: &lsquo;string&rsquo; - Adafruit IO feed key for &lsquo;humidity&rsquo; feed</p>
</li>
</ul>
<h3 id="misc-settings-for-data-management">Misc. Settings for Data Management</h3>
<ul>
<li><strong>UNITS_TEMPS</strong>: &lsquo;string&rsquo; - temperature sensor reads in &ldquo;C&rdquo;, but data can also be converted to other units for display and upload.
<ul>
<li>
<p>&ldquo;C&rdquo; - <em>Celsius</em></p>
</li>
<li>
<p>&ldquo;F&rdquo; - <em>Fahrenheit - data will be converted from Celsius to Fahrenheit</em></p>
</li>
<li>
<p>&ldquo;K&rdquo; - <em>Kelvin - data will be converted from Celsius to Kelvin</em></p>
</li>
<li>
<p><em>Example: &ldquo;F&rdquo; means temperature data will be converted from Celsius to Fahrenheit before it is uploaded or displayed.</em></p>
</li>
</ul>
</li>
</ul>
<p><strong>NOTE:</strong> THIS SETTING IS RESERVED FOR FUTURE USE</p>
<h3 id="misc-application-defaults">Misc. Application Defaults</h3>
<ul>
<li>
<p><strong>ROTATION</strong>: &lsquo;int&rsquo; - 0 | 90 | 180 | 270 degrees to turn LCD display</p>
<ul>
<li>90 | 270 - <em>top of LCD will point toward/away RPI HDMI and layout is 160x80</em></li>
<li>0 | 180 - <em>top of LCD will point away/toward RPI USB and layout is 80x160</em></li>
</ul>
</li>
<li>
<p><strong>DISPLAY</strong>: &lsquo;str&rsquo;</p>
<ul>
<li>&rsquo;name_of_display_mode&rsquo; - <em>name of display mode with single data point (e.g. download speed, etc.) and scrolling bar graph</em></li>
<li>&lsquo;all&rsquo; - <em>displays all collected data as text in dual columns</em></li>
<li>&lsquo;sparkles&rsquo; - <em>default display is in &lsquo;sparkle&rsquo; mode where data is collected and uploaded but not displayed</em></li>
</ul>
</li>
<li>
<p><strong>DELAY</strong>: &lsquo;int&rsquo; - delay in seconds between uploads to Adafruit IO.</p>
<ul>
<li>Smaller number means more freq uploads and higher data rate</li>
</ul>
</li>
<li>
<p><strong>WAIT</strong>: &lsquo;int&rsquo; - delay in seconds between sensor reads</p>
</li>
<li>
<p><strong>THROTTLE</strong>: &lsquo;int&rsquo; - additional delay in seconds to be applied on Adafruit IO &lsquo;ThrottlingError&rsquo;</p>
</li>
<li>
<p><strong>PROGRESS</strong>: &lsquo;string&rsquo; - on | off</p>
<ul>
<li>&ldquo;on&rdquo; - <em>show &lsquo;wait for upload&rsquo; progress bar on LCD</em></li>
<li>&ldquo;off&rdquo; - <em>do not show progress bar</em></li>
</ul>
</li>
<li>
<p><strong>SLEEP</strong>: &lsquo;int&rsquo; - delay in seconds until LCD is blanked for &ldquo;screen saver&rdquo; mode</p>
</li>
<li>
<p><strong>LOGLVL</strong>: &lsquo;string&rsquo; - debug | info | error</p>
<ul>
<li><em>Logging levels (see: <a href="https://docs.python.org/3/library/logging.html#logging-levels">Python docs</a> for more info)</em></li>
</ul>
</li>
<li>
<p><strong>LOGFILE</strong>: &lsquo;string&rsquo; - path and file name for log file</p>
</li>
</ul>
]]>
      </content:encoded>
    </item>
    
    <item>
      <title>f451 Labs RPI SenseMon Application</title>
      <link>https://thinkinganalog.com/projects/f451-labs-rpi-sensemon-app/</link>
      <pubDate>Mon, 01 Jan 2024 00:00:00 +0000</pubDate>
      
      <guid>https://thinkinganalog.com/projects/f451-labs-rpi-sensemon-app/</guid>
      <description>
      
          
            
            
            <![CDATA[<img src="https://thinkinganalog.com/projects/f451-labs-rpi-sensemon-app/f451-labs-sensemon-cli-1200x800b-min_hu_9fb02043ef8bca91.jpg" width="640" height="427"/><br>]]>
          
        
      <![CDATA[ The *f451 Labs SenseMon* application is designed to run RPIs which are equipped with a Sense HAT add-ons. The main objective is to continously read environment data and upload the data to a cloud service.]]>
      </description>
      <content:encoded>
      
          
            
            
            <![CDATA[<img src="https://thinkinganalog.com/projects/f451-labs-rpi-sensemon-app/f451-labs-sensemon-cli-1200x800b-min_hu_9fb02043ef8bca91.jpg" width="640" height="427"/><br>]]>
          
        
      <![CDATA[ 

<div class="notices note" ><p>This application is running on my <a href="https://thinkinganalog.com/projects/f451-labs-pired"><em>f451 Labs piRED</em> device</a>.</p></div>

<h2 id="overview">Overview</h2>
<p>This application is designed for my <a href="https://thinkinganalog.com/projects/f451-labs-pired"><em>f451 Labs piRED</em></a> and <a href="https://thinkinganalog.com/projects/f451-labs-pif451"><em>piF451</em></a> devices, which are both equipped with <a href="https://www.raspberrypi.com/documentation/accessories/sense-hat.html">Raspberry Pi Sense HAT</a> add-ons. The main objective is to continuously read environment data (e.g., temperature, barometric pressure, and humidity) from the Sense HAT sensors and then upload the data to the <a href="https://io.adafruit.com">Adafruit IO service</a>.</p>
<h2 id="install">Install</h2>
<p>This application is not available on PyPi. However, you can still use <code>pip</code> to install the module directly from GitHub (see below).</p>
<h3 id="dependencies">Dependencies</h3>
<p>This module is dependent on the following libraries:</p>
<ul>
<li><a href="https://pypi.org/project/sense-hat/">sense-hat</a> — only install if you have a physical Sense HAT device</li>
<li><a href="https://pypi.org/project/adafruit-io/">adafruit-io</a> — only install if you have an account with the Adafruit IO service</li>
</ul>
<p>NOTE: You can run this app in demo mode on (almost) any device, even without the Sense HAT. It will then create random numbers and can send output to the <code>logger</code> when log level is <code>DEBUG</code> or when <code>--debug</code> flag is used.</p>
<h3 id="installing-from-github-using-pip">Installing from GitHub using <code>pip</code></h3>
<p>You can use <code>pip install</code> to install this module directly from GitHub as follows:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>$ pip install <span style="color:#e6db74">&#39;f451-piRED @ git+https://github.com/mlanser/f451-piRED.git&#39;</span>
</span></span></code></pre></div><h3 id="whats-with-the-name-f451-pired">What&rsquo;s with the name &lsquo;<em>f451-piRED</em>&rsquo;</h3>
<p>The original idea behind this repo was to hold all applications running on this particular Raspberry Pi device — <a href="https://thinkinganalog.com/projects/f451-labs-pired">piRED</a> — in my network. This device has a specific hardware configuration and general &ldquo;purpose&rdquo; (i.e. to read and process environment data).</p>
<p>So, if/when I add more applications to this device, they&rsquo;ll also be added to this repo and show up as &lsquo;scripts&rsquo; entry points in the <code>pyprojects.toml</code> file.</p>
<h2 id="how-to-use">How to use</h2>
<h3 id="running-the-application">Running the application</h3>
<p>The <code>sensemon</code> application is designed to run unsupervised, and it will collect and upload data until it is interrupted by some external event (e.g. keyboard interrupt, process <code>kill</code> command, etc.)</p>
<p>To launch this application from a terminal:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>$ nohup python -u sensemon.py &gt; sensemon.out &amp;
</span></span></code></pre></div><p>This command launches the <code>sensemon</code> application in the background. The application will keep running even after the terminal window is closed. Any output will be redirected to the <code>sensemon.out</code> file.</p>
<p>It&rsquo;s also possible to install this application via <code>pip</code> from GitHub, and one can then launch the application as follows:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>$ nohup sensemon &gt; sensemon.out &amp;
</span></span></code></pre></div><h3 id="interacting-with-the-application">Interacting with the application</h3>
<p>The <code>sensemon</code> application can read settings from both a <code>settings.toml</code> file and from CLI arguments:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># Use CLI arg &#39;-h&#39; to see available options</span>
</span></span><span style="display:flex;"><span>$ sensemon -h 
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Stop after 10 uploads</span>
</span></span><span style="display:flex;"><span>$ sensemon --uploads <span style="color:#ae81ff">10</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Show &#39;progress bar&#39; regardless of setting in &#39;toml&#39; file</span>
</span></span><span style="display:flex;"><span>$ sensemon --progress
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Show specific display mode (e.g. &#39;temperature&#39;) regardless </span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># of setting in &#39;toml&#39; file</span>
</span></span><span style="display:flex;"><span>$ sensemon --dmode temperature
</span></span></code></pre></div><p>The format of the <code>settings.toml</code> file is straightforward, and this is also where you should store Adafruit IO credentials. The <code>settings.toml</code> file only supports numbers and strings. But you define most aspects of the applications here.</p>
<p>For example, if you change the <code>PROGRESS</code> setting to 1, then the Sense HAT LED will display a progress bar indicating when the next (simulated) upload will happen.</p>
<p>A &lsquo;sleep mode&rsquo; also turns off the display automatically after a certain amount of time, and you can also turn the LED display on/off by pushing/tapping the joystick button (down).</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-toml" data-lang="toml"><span style="display:flex;"><span><span style="color:#75715e"># File: settings.toml</span>
</span></span><span style="display:flex;"><span>...
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">PROGRESS</span> = <span style="color:#ae81ff">1</span>    <span style="color:#75715e"># [0|1] - 1 = show upload progress bar on LED</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">SLEEP</span> = <span style="color:#ae81ff">600</span>     <span style="color:#75715e"># Delay in seconds until screen is blanked</span>
</span></span><span style="display:flex;"><span>...
</span></span></code></pre></div><p>Please refer to the section &ldquo;<em>Custom application settings in SETTINGS.TOML</em>&rdquo; below for more information on available options in the <code>settings.toml</code> file.</p>
<p>The <code>sensemon</code> application can display live data in the terminal and on the Sense HAT LED. If you do not want to see any output in the terminal (e.g. if you want to run the application in the background), then you can start the application with the <code>--noCLI</code> flag. Similarly, the <code>--noLED</code> flag prevents any output to the Sense HAT LED.</p>
<p>This application offers 4 different display modes for the Sense HAT LED:</p>
<ul>
<li><em>temperature</em> — show realtime graph of current temperature data</li>
<li><em>pressure</em> — show realtime graph of current baromteric pressure data</li>
<li><em>humidity</em> — show realtime graph of current humidity data</li>
<li><em>sparkles</em> — show random pixels light up — looks great at night and lets you know the app is running 😉</li>
</ul>
<p>You can switch between display modes by pushing the Sense HAT joystick left or right and rotating the display by pushing the joystick up or down. And again, you can turn the LED display on/off by tapping (pushing straight down) the joystick in the middle.</p>
<p>Finally, you can exit the application using the <code>ctrl-c</code> command. If you use the <code>--uploads N</code> command line argument, the application will stop after <em>N</em> (simulated) uploads.</p>
<h2 id="how-to-test">How to test</h2>


<div class="notices info" ><p>This test suite is still very much WIP.</p></div>

<p>The tests are written for <a href="https://docs.pytest.org/en/7.1.x/contents.html">pytest</a>, and we use markers to separate out tests that require the actual Sense HAT hardware. Some tests do not rely on the hardware to be present. However, those tests rely on the <code>pytest-mock</code> module to be present.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># Run all tests (except marked &#39;skip&#39;)</span>
</span></span><span style="display:flex;"><span>$ pytest
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Run tests with &#39;hardware&#39; marker</span>
</span></span><span style="display:flex;"><span>$ pytest -m <span style="color:#e6db74">&#34;hardware&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Run tests without &#39;hardware&#39; marker</span>
</span></span><span style="display:flex;"><span>$ pytest -m <span style="color:#e6db74">&#34;not hardware&#34;</span>
</span></span></code></pre></div><h2 id="custom-application-settings-in-settingstoml">Custom application settings in SETTINGS.TOML</h2>
<p>The &lsquo;settings.toml&rsquo; file holds various custom application settings and secrets (e.g. Adafruit IO keys, etc.), and this file should <strong>NOT</strong> be included in &lsquo;git&rsquo; commits.</p>
<p>It is recommended to copy the &lsquo;<em>settings.example</em>&rsquo; to &lsquo;<em>settings.toml</em>&rsquo; and then customize the values in &lsquo;<em>settings.toml</em>&rsquo; as needed for the specific device that the application is running on.</p>
<h3 id="adafruit-io-settings">Adafruit IO settings</h3>
<ul>
<li>
<p><strong>AIO_USERNAME</strong>: &lsquo;string&rsquo; - Adafruit IO username</p>
</li>
<li>
<p><strong>AIO_KEY</strong>: &lsquo;string&rsquo; - Adafruit IO key</p>
</li>
<li>
<p><strong>AIO_UPLOAD</strong>: &lsquo;string&rsquo; - yes | force | no</p>
<ul>
<li>&ldquo;yes&rdquo; - <em>upload if feed available</em></li>
<li>&ldquo;force&rdquo; - <em>exit if feed invalid</em></li>
<li>&ldquo;no&rdquo; - <em>do not upload data</em></li>
</ul>
</li>
<li>
<p><strong>FEED_TEMPS</strong>: &lsquo;string&rsquo; - Adafruit IO feed key for &rsquo;temperature&rsquo; feed</p>
</li>
<li>
<p><strong>FEED_PRESS</strong>: &lsquo;string&rsquo; - Adafruit IO feed key for &lsquo;pressure&rsquo; feed</p>
</li>
<li>
<p><strong>FEED_HUMID</strong>: &lsquo;string&rsquo; - Adafruit IO feed key for &lsquo;humidity&rsquo; feed</p>
</li>
</ul>
<h3 id="misc-settings-for-data-management">Misc. Settings for Data Management</h3>
<ul>
<li><strong>UNITS_TEMPS</strong>: &lsquo;string&rsquo; - temperature sensor reads in &ldquo;C&rdquo;, but data can also be converted to other units for display and upload.
<ul>
<li>
<p>&ldquo;C&rdquo; - <em>Celsius</em></p>
</li>
<li>
<p>&ldquo;F&rdquo; - <em>Fahrenheit - data will be converted from Celsius to Fahrenheit</em></p>
</li>
<li>
<p>&ldquo;K&rdquo; - <em>Kelvin - data will be converted from Celsius to Kelvin</em></p>
</li>
<li>
<p><em>Example: &ldquo;F&rdquo; means temperature data will be converted from Celsius to Fahrenheit before it is uploaded or displayed.</em></p>
</li>
</ul>
</li>
</ul>
<p><strong>NOTE:</strong> THIS SETTING IS RESERVED FOR FUTURE USE</p>
<h3 id="misc-application-defaults">Misc. Application Defaults</h3>
<ul>
<li>
<p><strong>ROTATION</strong>: &lsquo;int&rsquo; - 0 | 90 | 180 | 270 degrees to turn 8x8 LED display</p>
<ul>
<li>90 | 270 - <em>top of LED will point toward/away RPI HDMI</em></li>
<li>0 | 180 - <em>top of LED will point away/toward RPI USB</em></li>
</ul>
</li>
<li>
<p><strong>DISPLAY</strong>: &lsquo;str&rsquo;</p>
<ul>
<li>&rsquo;name_of_display_mode&rsquo; - <em>name of display mode with single data point (e.g. temperature, etc.) and scrolling bar graph</em></li>
<li>&lsquo;sparkles&rsquo; - <em>default display is in &lsquo;sparkle&rsquo; mode where data is collected and uploaded but not displayed</em></li>
</ul>
</li>
<li>
<p><strong>DELAY</strong>: &lsquo;int&rsquo; - delay in seconds between uploads to Adafruit IO.</p>
<ul>
<li>Smaller number means more freq uploads and higher data rate</li>
</ul>
</li>
<li>
<p><strong>WAIT</strong>: &lsquo;int&rsquo; - delay in seconds between sensor reads</p>
</li>
<li>
<p><strong>THROTTLE</strong>: &lsquo;int&rsquo; - additional delay in seconds to be applied on Adafruit IO &lsquo;ThrottlingError&rsquo;</p>
</li>
<li>
<p><strong>PROGRESS</strong>: &lsquo;string&rsquo; - on | off</p>
<ul>
<li>&ldquo;on&rdquo; - <em>show &lsquo;wait for upload&rsquo; progress bar on LED</em></li>
<li>&ldquo;off&rdquo; - <em>do not show progress bar</em></li>
</ul>
</li>
<li>
<p><strong>SLEEP</strong>: &lsquo;int&rsquo; - delay in seconds until LED is blanked for &ldquo;screen saver&rdquo; mode</p>
</li>
<li>
<p><strong>LOGLVL</strong>: &lsquo;string&rsquo; - debug | info | error</p>
<ul>
<li><em>Logging levels (see: <a href="https://docs.python.org/3/library/logging.html#logging-levels">Python docs</a> for more info)</em></li>
</ul>
</li>
<li>
<p><strong>LOGFILE</strong>: &lsquo;string&rsquo; - path and file name for log file</p>
</li>
</ul>
]]>
      </content:encoded>
    </item>
    
    <item>
      <title>f451 Labs RPI SysMon Application</title>
      <link>https://thinkinganalog.com/projects/f451-labs-rpi-sysmon-app/</link>
      <pubDate>Mon, 01 Jan 2024 00:00:00 +0000</pubDate>
      
      <guid>https://thinkinganalog.com/projects/f451-labs-rpi-sysmon-app/</guid>
      <description>
      
          
            
            
            <![CDATA[<img src="https://thinkinganalog.com/projects/f451-labs-rpi-sysmon-app/f451-labs-sysmon-cli-1200x800-min_hu_67cdda36c429d33c.jpg" width="640" height="427"/><br>]]>
          
        
      <![CDATA[ The *f451 Labs SysMon* application is designed to run RPIs which are equipped with a Sense HAT add-ons. The main objective is to continously run internet speed tests (using speedtest-cli) and upload the data to a cloud service.]]>
      </description>
      <content:encoded>
      
          
            
            
            <![CDATA[<img src="https://thinkinganalog.com/projects/f451-labs-rpi-sysmon-app/f451-labs-sysmon-cli-1200x800-min_hu_67cdda36c429d33c.jpg" width="640" height="427"/><br>]]>
          
        
      <![CDATA[ 

<div class="notices note" ><p>This application is running on my <a href="https://thinkinganalog.com/projects/f451-labs-pif451"><em>f451 Labs piF451</em> device</a>.</p></div>

<h2 id="overview">Overview</h2>
<p>This application is designed for my <a href="https://thinkinganalog.com/projects/f451-labs-pif451"><em>f451 Labs piF451</em></a> and <a href="https://thinkinganalog.com/projects/f451-labs-pired"><em>piRED</em></a> devices, which are both equipped with <a href="https://www.raspberrypi.com/documentation/accessories/sense-hat.html">Raspberry Pi Sense HAT</a> add-ons. The main objective is continuously running internet speed tests using the <code>speedtest-cli</code> library and then upload data to the <a href="https://io.adafruit.com">Adafruit IO service</a>.</p>
<h2 id="install">Install</h2>
<p>This application is not available on PyPi. However, you can still use <code>pip</code> to install the module directly from GitHub (see below).</p>
<h3 id="dependencies">Dependencies</h3>
<p>This module is dependent on the following libraries:</p>
<ul>
<li><a href="https://pypi.org/project/speedtest-cli/">speedtest-cli</a> - only used for internet speed tests</li>
<li><a href="https://pypi.org/project/sense-hat/">sense-hat</a> — only install if you have a physical Sense HAT device</li>
<li><a href="https://pypi.org/project/adafruit-io/">adafruit-io</a> — only install if you have an account with the Adafruit IO service</li>
</ul>
<p>NOTE: You can run this app in demo mode on (almost) any device, even without the Sense HAT. It will then create random numbers and can send output to the <code>logger</code> when log level is <code>DEBUG</code> or when <code>--debug</code> flag is used.</p>
<h3 id="installing-from-github-using-pip">Installing from GitHub using <code>pip</code></h3>
<p>You can use <code>pip install</code> to install this module directly from GitHub as follows:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>$ pip install <span style="color:#e6db74">&#39;f451-piF451 @ git+https://github.com/mlanser/f451-piF451.git&#39;</span>
</span></span></code></pre></div><h3 id="whats-with-the-name-f451-pif451">What&rsquo;s with the name &lsquo;<em>f451-piF451</em>&rsquo;</h3>
<p>The original idea behind this repo was to hold all applications running on a particular Raspberry Pi device — <a href="https://thinkinganalog.com/projects/f451-labs-pif451">piF451</a> — in my network. This device has a specific hardware configuration and general &ldquo;purpose&rdquo; (i.e. to collect and process internet speed data).</p>
<p>So, if/when I add more applications to this device, they&rsquo;ll also be added to this repo and show up as &lsquo;scripts&rsquo; entry points in the <code>pyprojects.toml</code> file.</p>
<h2 id="how-to-use">How to use</h2>
<h3 id="running-the-application">Running the application</h3>
<p>The <code>sysmon</code> application is designed to run unsupervised, and it will collect and upload data until it is interrupted by some external event (e.g. keyboard interrupt, process <code>kill</code> command, etc.)</p>
<p>To launch this application from a terminal:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>$ nohup python -u sysmon.py &gt; sysmon.out &amp;
</span></span></code></pre></div><p>This command launches the <code>sysmon</code> application in the background. The application will keep running even after the terminal window is closed. Any output will be redirected to the <code>sysmon.out</code> file.</p>
<p>It&rsquo;s also possible to install this application via <code>pip</code> from GitHub, and one can then launch the application as follows:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>$ nohup sysmon &gt; sysmon.out &amp;
</span></span></code></pre></div><h3 id="interacting-with-the-application">Interacting with the application</h3>
<p>The <code>sysmon</code> application can read settings from both a <code>settings.toml</code> file and from CLI arguments:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># Use CLI arg &#39;-h&#39; to see available options</span>
</span></span><span style="display:flex;"><span>$ sysmon -h 
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Stop after 10 uploads</span>
</span></span><span style="display:flex;"><span>$ sysmon --uploads <span style="color:#ae81ff">10</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Show &#39;progress bar&#39; regardless of setting in &#39;toml&#39; file</span>
</span></span><span style="display:flex;"><span>$ sysmon --progress
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Show specific display mode (e.g. &#39;download&#39; speed) regardless </span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># of setting in &#39;toml&#39; file</span>
</span></span><span style="display:flex;"><span>$ sysmon --dmode download
</span></span></code></pre></div><p>The format of the <code>settings.toml</code> file is straightforward, and this is also where you should store Adafruit IO credentials. The <code>settings.toml</code> file only supports numbers and strings. But you define most aspects of the applications here.</p>
<p>For example, if you change the <code>PROGRESS</code> setting to 1, then the Sense HAT LED will display a progress bar indicating when the next (simulated) upload will happen.</p>
<p>A &lsquo;sleep mode&rsquo; also turns off the display automatically after a certain amount of time, and you can also turn the LED display on/off by pushing/tapping the joystick button (down).</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-toml" data-lang="toml"><span style="display:flex;"><span><span style="color:#75715e"># File: settings.toml</span>
</span></span><span style="display:flex;"><span>...
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">PROGRESS</span> = <span style="color:#ae81ff">1</span>    <span style="color:#75715e"># [0|1] - 1 = show upload progress bar on LED</span>
</span></span><span style="display:flex;"><span><span style="color:#a6e22e">SLEEP</span> = <span style="color:#ae81ff">600</span>     <span style="color:#75715e"># Delay in seconds until screen is blanked</span>
</span></span><span style="display:flex;"><span>...
</span></span></code></pre></div><p>Please refer to the section &ldquo;<em>Custom application settings in SETTINGS.TOML</em>&rdquo; below for more information on available options in the <code>settings.toml</code> file.</p>
<p>The <code>sysmon</code> application can display live data in the terminal and on the Sense HAT LED. If you do not want to see any output in the terminal (e.g. if you&rsquo;re going to run the application in the background), you can start the application with the <code>--noCLI</code> flag. Similarly, the <code>--noLED</code> flag prevents any output to the Sense HAT LED.</p>
<p>This application offers 4 different display modes for the Sense HAT LED:</p>
<ul>
<li><em>download</em> — show realtime graph of current download speed</li>
<li><em>upload</em> — show realtime graph of current upload speed</li>
<li><em>ping</em> — show realtime graph of ping response time</li>
<li><em>sparkles</em> — show random pixels light up — looks great at night and lets you know the app is running 😉</li>
</ul>
<p>You can switch between display modes by pushing the Sense HAT joystick left or right and rotating the display by pushing the joystick up or down. And again, you can turn the LED display on/off by tapping (pushing straight down) the joystick in the middle.</p>
<p>Finally, you can exit the application using the <code>ctrl-c</code> command. If you use the <code>--uploads N</code> command line argument, the application will stop after <em>N</em> (simulated) uploads.</p>
<p><strong>NOTE:</strong> It takes a bit of time to run the actual speed test, and you&rsquo;ll probably only want to run this every few minutes. This obviously slows down the &lsquo;realtime&rsquo; display. However, this application is really designed to run in the background, and you&rsquo;ll most likely only want to see &ldquo;realtime&rdquo; graph data output to the terminal and/or Sense HAT LED when you&rsquo;re configuring and/or testing the application.</p>
<h2 id="how-to-test">How to test</h2>


<div class="notices info" ><p>This test suite is still very much WIP.</p></div>

<p>The tests are written for <a href="https://docs.pytest.org/en/7.1.x/contents.html">pytest</a>, and we use markers to separate out tests that require the actual Sense HAT hardware. Some tests do not rely on the hardware to be present. However, those tests rely on the <code>pytest-mock</code> module to be present.</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># Run all tests (except marked &#39;skip&#39;)</span>
</span></span><span style="display:flex;"><span>$ pytest
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Run tests with &#39;hardware&#39; marker</span>
</span></span><span style="display:flex;"><span>$ pytest -m <span style="color:#e6db74">&#34;hardware&#34;</span>
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># Run tests without &#39;hardware&#39; marker</span>
</span></span><span style="display:flex;"><span>$ pytest -m <span style="color:#e6db74">&#34;not hardware&#34;</span>
</span></span></code></pre></div><h2 id="custom-application-settings-in-settingstoml">Custom application settings in SETTINGS.TOML</h2>
<p>The &lsquo;settings.toml&rsquo; file holds various custom application settings and secrets (e.g. Adafruit IO keys, etc.), and this file should <strong>NOT</strong> be included in &lsquo;git&rsquo; commits.</p>
<p>It is recommended to copy the &lsquo;<em>settings.example</em>&rsquo; to &lsquo;<em>settings.toml</em>&rsquo; and then customize the values in &lsquo;<em>settings.toml</em>&rsquo; as needed for the specific device that the application is running on.</p>
<h3 id="adafruit-io-settings">Adafruit IO settings</h3>
<ul>
<li>
<p><strong>AIO_USERNAME</strong>: &lsquo;string&rsquo; - Adafruit IO username</p>
</li>
<li>
<p><strong>AIO_KEY</strong>: &lsquo;string&rsquo; - Adafruit IO key</p>
</li>
<li>
<p><strong>AIO_UPLOAD</strong>: &lsquo;string&rsquo; - yes | force | no</p>
<ul>
<li>&ldquo;yes&rdquo; - <em>upload if feed available</em></li>
<li>&ldquo;force&rdquo; - <em>exit if feed invalid</em></li>
<li>&ldquo;no&rdquo; - <em>do not upload data</em></li>
</ul>
</li>
<li>
<p><strong>FEED_DWNLD</strong>: &lsquo;string&rsquo; - Adafruit IO feed key for &lsquo;download&rsquo; feed</p>
</li>
<li>
<p><strong>FEED_UPLD</strong>: &lsquo;string&rsquo; - Adafruit IO feed key for &lsquo;upload&rsquo; feed</p>
</li>
<li>
<p><strong>FEED_PING</strong>: &lsquo;string&rsquo; - Adafruit IO feed key for &lsquo;ping&rsquo; feed</p>
</li>
</ul>
<h3 id="misc-application-defaults">Misc. Application Defaults</h3>
<ul>
<li>
<p><strong>ROTATION</strong>: &lsquo;int&rsquo; - 0 | 90 | 180 | 270 degrees to turn 8x8 LED display</p>
<ul>
<li>90 | 270 - <em>top of LED will point toward/away RPI HDMI</em></li>
<li>0 | 180 - <em>top of LED will point away/toward RPI USB</em></li>
</ul>
</li>
<li>
<p><strong>DISPLAY</strong>: &lsquo;str&rsquo;</p>
<ul>
<li>&rsquo;name_of_display_mode&rsquo; - <em>name of display mode with single data point (e.g. download speed, etc.) and scrolling bar graph</em></li>
<li>&lsquo;sparkles&rsquo; - <em>default display is in &lsquo;sparkle&rsquo; mode where data is collected and uploaded but not displayed</em></li>
</ul>
</li>
<li>
<p><strong>DELAY</strong>: &lsquo;int&rsquo; - delay in seconds between uploads to Adafruit IO.</p>
<ul>
<li>Smaller number means more freq uploads and higher data rate</li>
</ul>
</li>
<li>
<p><strong>WAIT</strong>: &lsquo;int&rsquo; - delay in seconds between sensor reads</p>
</li>
<li>
<p><strong>THROTTLE</strong>: &lsquo;int&rsquo; - additional delay in seconds to be applied on Adafruit IO &lsquo;ThrottlingError&rsquo;</p>
</li>
<li>
<p><strong>PROGRESS</strong>: &lsquo;string&rsquo; - on | off</p>
<ul>
<li>&ldquo;on&rdquo; - <em>show &lsquo;wait for upload&rsquo; progress bar on LED</em></li>
<li>&ldquo;off&rdquo; - <em>do not show progress bar</em></li>
</ul>
</li>
<li>
<p><strong>SLEEP</strong>: &lsquo;int&rsquo; - delay in seconds until LED is blanked for &ldquo;screen saver&rdquo; mode</p>
</li>
<li>
<p><strong>LOGLVL</strong>: &lsquo;string&rsquo; - debug | info | error</p>
<ul>
<li><em>Logging levels (see: <a href="https://docs.python.org/3/library/logging.html#logging-levels">Python docs</a> for more info)</em></li>
</ul>
</li>
<li>
<p><strong>LOGFILE</strong>: &lsquo;string&rsquo; - path and file name for log file</p>
</li>
</ul>
]]>
      </content:encoded>
    </item>
    
    <item>
      <title>December 2023</title>
      <link>https://thinkinganalog.com/notes/december-2023/</link>
      <pubDate>Sun, 31 Dec 2023 00:00:00 +0000</pubDate>
      
      <guid>https://thinkinganalog.com/notes/december-2023/</guid>
      <description>
      
          
            
            
            <![CDATA[<img src="https://thinkinganalog.com/notes/december-2023/pexels-ylanite-koppens-5959473-1200x800-min_hu_b3770e4d822445da.jpg" width="640" height="427"/><br>]]>
          
        
      <![CDATA[ December — we made it through yet another year. No travel. Quiet holidays. Vacation. A bit of time for some programming 🤓]]>
      </description>
      <content:encoded>
      
          
            
            
            <![CDATA[<img src="https://thinkinganalog.com/notes/december-2023/pexels-ylanite-koppens-5959473-1200x800-min_hu_b3770e4d822445da.jpg" width="640" height="427"/><br>]]>
          
        
      <![CDATA[ <p>Phew! We made it through 2023 in more or less one piece. What a year! Sold an old home and moved to a new city. Went from endless yard work on weekends to relaxing do-whatever-I-want weekends. A trip to Europe. A teenager went back to college. And yes, even this year, COVID is still a thing, so we got yet another booster.</p>
<p>Here is December:</p>
<ul>
<li><strong>No business trips</strong> — there was no need to travel this month, which is actually kinda nice.</li>
<li><strong>Holidays and vacation</strong> — Christmas and New Year&rsquo;s Eve were nice and quiet. Vacation time to recharge. It was a long year, and it felt nice not doing much of anything for a bit!</li>
<li><strong>No yardwork &hellip; yay!</strong> — no leaves to rake, no weeds to keep after, no tree branches to trim, no gophers to chase 🙂</li>
<li><strong>New projects</strong> — have been coding a bit and writing about it &hellip; so much fun! 🤓</li>
<li><strong>Not sure I&rsquo;m looking forward to the new year</strong> — already know that 2024 will be a crazy year. It&rsquo;ll be a busy year. Lots of things are planned. And lots of stuff will happen whether we want to or not. But, one day at a time &hellip; right? 🙂</li>
</ul>
<p>Short version: December — we made it through yet another year. No travel. Quiet holidays. Vacation. A bit of time for some programming 🤓</p>
]]>
      </content:encoded>
    </item>
    
    <item>
      <title>f451 Labs piEnviro - Collect Data With Enviro&#43;</title>
      <link>https://thinkinganalog.com/projects/f451-labs-pienviro/</link>
      <pubDate>Sat, 02 Dec 2023 00:00:00 +0000</pubDate>
      
      <guid>https://thinkinganalog.com/projects/f451-labs-pienviro/</guid>
      <description>
      
          
            
            
            <![CDATA[<img src="https://thinkinganalog.com/projects/f451-labs-pienviro/f451-labs-pienviro-1200x800b-min_hu_e86eeea6bf7180df.jpg" width="640" height="427"/><br>]]>
          
        
      <![CDATA[ The main objective of this project is to collect environment data, upload it to the cloud, and display some form of progress on an onboard display.]]>
      </description>
      <content:encoded>
      
          
            
            
            <![CDATA[<img src="https://thinkinganalog.com/projects/f451-labs-pienviro/f451-labs-pienviro-1200x800b-min_hu_e86eeea6bf7180df.jpg" width="640" height="427"/><br>]]>
          
        
      <![CDATA[ <h2 id="overview">Overview</h2>
<p>The main objective of this project is to collect environment data, upload it to the cloud, and display some form of progress on an onboard display. This <a href="https://raspberrypi.org">Raspberry Pi</a> has a <a href="https://learn.pimoroni.com/article/getting-started-with-enviro-plus">Pimoroni Enviro+ HAT</a> with an 0.96&quot; LCD.</p>
<p>This particular Raspberry Pi device currently runs one application — <a href="https://thinkinganalog.com/projects/f451-labs-rpi-enviromon-app"><em>enviromon</em></a> — and the main task is to collect miscellaneous indoor environment data, upload to various <a href="https://io.adafruit.com">Adafruit IO</a> feeds, and, of course, also display in realtime on the onboard LCD.</p>
<p>We&rsquo;re using the Enviro+ light sensor to allow the user to switch display modes to show different environment data as graphs or text. To switch mode, one simply covers the light sensor for a bit with a hand or piece of paper. And yes, there is also a &ldquo;Sparkle Mode&rdquo; and &ldquo;Sleep Mode&rdquo; where the display is blank 😊</p>
<h2 id="device-specifications--configuration">Device specifications &amp; configuration</h2>
<h3 id="general-specifications">General specifications</h3>
<p>I decided to use an older Raspberry Pi as there&rsquo;s not much needed to run the monitoring application. The device is headless and we&rsquo;re therefore running the OS without the GUI (desktop).</p>
<ul>
<li>Device: <a href="https://www.raspberrypi.com/products/raspberry-pi-3-model-b/">RP3</a> - Model B Rev 1.2 / 1GB - <a href="https://www.raspberrypi.com/software/operating-systems/#raspberry-pi-os-legacy">Bullseye (Debian 11)</a> / 32bit</li>
<li>Network: wlan0 (wifi)</li>
<li>Display &amp; keyboard: none</li>
<li>Other hardware: <a href="https://learn.pimoroni.com/article/getting-started-with-enviro-plus">Pimoroni Enviro+ HAT</a></li>
<li>Remote access: SSH</li>
</ul>
<h3 id="main-tools--applications">Main tools &amp; applications</h3>
<p>This device is configured to run a single Python application. But I&rsquo;ve still added a few tools to make life easier when I need to debug stuff after things go sideways.</p>
<ul>
<li><strong><a href="https://networkmanager.dev/">NetworkManager</a></strong> — my default tool for managing network settings on my RPIs</li>
<li><strong><a href="https://help.ubuntu.com/community/UFW">UFW (firewall)</a></strong> — my default tool for managing firewall settings on my RPIs</li>
<li><strong><a href="https://htop.dev/">htop</a></strong> — my default process viewer/manager on my RPIs</li>
<li><strong>Misc. tools</strong> — e.g. <a href="https://pypa.github.io/pipx/">PIPX</a>, <a href="https://git-scm.com/">git</a>, etc.</li>
</ul>
<p>As a side note, most of my devices are configured in similar ways with (mostly) the same tools. And while some devices have GUIs, most do not, and I usually access all devices from my laptop via SSH.</p>
<h2 id="common-workflows">Common workflows</h2>
<p>Given its role as a single-purpose monitoring device, there is essentially only one workflow (aside from maintaining the device itself): install and run monitoring applications.</p>
<p>My CLI applications can be installed via the <code>pip</code> command, so the workflow is straightforward. Although, I have switched to using the <code>pipx</code> command to ensure that whatever application I install does not &ldquo;pollute&rdquo; the Python environment on this Raspberry Pi device.</p>
<p>Now, one additional wrinkle is that my applications and packages are not hosted on PyPi. Instead, I install them directly from my GitHub repo as follows:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>$ pipx install git+ssh://&lt;username&gt;@github.com/&lt;path-to-my-app.git&gt;
</span></span></code></pre></div><p>This method allows me to install Python applications quickly, and I can run each CLI application by simply typing <code>my_app_name</code> in the terminal.</p>
<p>The <code>pipx install</code> command is very flexible, and several switches are available. For example, the <code>--python</code> switch allows us to define which version of Python (v3.6+) to use for the installation, which can be very useful when trying different scenarios.</p>
<p>It&rsquo;s also possible to use the <code>pipx upgrade</code> to upgrade one&rsquo;s application. However, that assumes that one first has bumped the version number in GitHub. Instead, I rerun the <code>pip install</code> command with the <code>--force</code> switch, which doesn&rsquo;t care whether the version has been bumped.</p>
<p>Finally, I do not install my applications in &ldquo;editable&rdquo; mode (using the <code>-e</code> switch) on this Raspberry Pi as I do not edit code directly on this device.</p>
<h2 id="summary">Summary</h2>
<p>Getting this Raspberry Pi up and running as a single-purpose device running a few CLI applications was trivial. However, it&rsquo;s worth noting that the goal is for this device to essentially never stop running. That means one needs to think through how to automate and streamline maintenance and support routines.</p>
<p>For example, from time to time, we&rsquo;ll need to update the OS, the various support libraries, etc. And, of course, every once in a while, we&rsquo;ll want to update the actual monitoring applications. Most maintenance tasks can be done without restarting the device. But there are occasions when the updates require a restart.</p>
<p>Finally, there are external events that may affect this device. For example, we had a day-long internet outage not too long ago, and when everything came back online, we had to restart the router. Then, there have been power outages in the neighborhood. And no, my home network of Raspberry Pis is not hosted in a data center with fail-over power, etc. So when the lights go out, the devices go down.</p>
<p>All this means that it&rsquo;s worth spending a bit of time creating easy (re-)start processes, upgrade scripts, and so on 😊</p>
]]>
      </content:encoded>
    </item>
    
    <item>
      <title>f451 Labs piF451 - System Monitor With Sense HAT</title>
      <link>https://thinkinganalog.com/projects/f451-labs-pif451/</link>
      <pubDate>Sat, 02 Dec 2023 00:00:00 +0000</pubDate>
      
      <guid>https://thinkinganalog.com/projects/f451-labs-pif451/</guid>
      <description>
      
          
            
            
            <![CDATA[<img src="https://thinkinganalog.com/projects/f451-labs-pif451/f451-labs-piF451-sysmon-1200x800-min_hu_b4fe17abb10ad6b.jpg" width="640" height="427"/><br>]]>
          
        
      <![CDATA[ The main objective of this project is to run one or more monitoring applications, which collect data, upload it to the cloud, and display some form of progress on an onboard display.]]>
      </description>
      <content:encoded>
      
          
            
            
            <![CDATA[<img src="https://thinkinganalog.com/projects/f451-labs-pif451/f451-labs-piF451-sysmon-1200x800-min_hu_b4fe17abb10ad6b.jpg" width="640" height="427"/><br>]]>
          
        
      <![CDATA[ <h2 id="overview">Overview</h2>
<p>The main objective of this project is to run one or more monitoring applications, which collect data, upload it to the cloud, and display some form of progress on an onboard display. This <a href="https://raspberrypi.org">Raspberry Pi</a> has a <a href="https://www.raspberrypi.com/documentation/accessories/sense-hat.html">Raspberry Pi Sense HAT</a> with an 8x8 LED display. And while the Sense HAT has several onboard sensors, we&rsquo;ll only use the display and joystick.</p>
<p>I have <a href="https://thinkinganalog.com/projects/f451-labs-pired">another Rasberry Pi equipped with a Sense HAT</a>, which collects data from the onboard sensor. And no, I can not for the life of me remember why I decided to get two Sense HATs. It turns out that I have bought many things over the years, but I cannot remember what projects I purchased them for 🤓</p>
<p>This particular Raspberry Pi device currently runs one application — <a href="https://thinkinganalog.com/projects/f451-labs-rpi-sysmon-app"><em>sysmon</em></a> — and the main task is to perform an internet speed test at regular intervals. This data is then uploaded to an <a href="https://io.adafruit.com">Adafruit IO</a> feed and displayed (crudely) on the onboard 8x8 LED display.</p>
<p>The Sense HAT joystick can switch display modes to show upload or download speeds and ping response times. There is even a &ldquo;Sparkle Mode,&rdquo; which simply lights up random LEDs. It&rsquo;s pretty at night, and it lets me know that the app is still running 😊</p>
<h2 id="device-specifications--configuration">Device specifications &amp; configuration</h2>
<h3 id="general-specifications">General specifications</h3>
<p>I decided to use this (fairly) powerful Raspberry Pi so that I can host various types of projects and websites without worrying much about performance.</p>
<ul>
<li>Device: <a href="https://www.raspberrypi.com/products/raspberry-pi-4-model-b/">RP4</a> - Model B Rev 1.1 / 4GB - <a href="https://www.raspberrypi.com/software/operating-systems/#raspberry-pi-os-64-bit">Bullseye (Debian 11)</a> / 64bit</li>
<li>Network: eth0 (wired)</li>
<li>Display &amp; keyboard: shared resources via KVM</li>
<li>Other hardware: <a href="https://www.raspberrypi.com/documentation/accessories/sense-hat.html">Raspberry Pi Sense HAT</a></li>
<li>Remote access: SSH, VNC</li>
</ul>
<h3 id="main-tools--applications">Main tools &amp; applications</h3>
<p>Most software on this device focuses on running various Python applications. But I&rsquo;ve also added a few tools to make life easier when I need to debug stuff after things go sideways.</p>
<ul>
<li><strong><a href="https://networkmanager.dev/">NetworkManager</a></strong> — my default tool for managing network settings on my RPIs</li>
<li><strong><a href="https://help.ubuntu.com/community/UFW">UFW (firewall)</a></strong> — my default tool for managing firewall settings on my RPIs</li>
<li><strong><a href="https://htop.dev/">htop</a></strong> — my default process viewer/manager on my RPIs</li>
<li><strong>Misc. tools</strong> — e.g. <a href="https://pypa.github.io/pipx/">PIPX</a>, <a href="https://git-scm.com/">git</a>, etc.</li>
</ul>
<p>As a side note, most of my devices are configured in similar ways with (mostly) the same tools. And while some devices have GUIs, most do not, and I usually access all devices from my laptop via SSH.</p>
<h3 id="custom-applications--scripts">Custom applications &amp; scripts</h3>
<p>This Raspberry Pi is configured the following applications and scripts:</p>
<ul>
<li><strong>sysmon</strong> — this application performs internet speed test checks using the <a href="https://www.speedtest.net/apps/cli"><em>SpeedTest CLI</em> library</a>. The data is uploaded to Adafruit IO and is also displayed in real-time on the onboard 8x8 LED display.</li>
</ul>


<div class="notices note" ><p>The <a href="https://thinkinganalog.com/projects/f451-labs-rpi-sysmon-app"><em>sysmon</em> application</a> is installed as part of the overall <a href="https://github.com/mlanser/f451-piF451"><em>f451-piF451</em></a> package. You can run it directly from the terminal when the package is installed with the <code>pip</code> or <code>pipx</code> commands (see below for more info).</p></div>

<h2 id="common-workflows">Common workflows</h2>
<p>Given its role as a single-purpose monitoring device, there is essentially only one workflow (aside from maintaining the device itself): install and run monitoring applications.</p>
<p>My CLI applications can be installed via the <code>pip</code> command, so the workflow is straightforward. Although, I have switched to using the <code>pipx</code> command to ensure that whatever application I install does not &ldquo;pollute&rdquo; the Python environment on this Raspberry Pi device.</p>
<p>Now, one additional wrinkle is that my applications and packages are not hosted on PyPi. Instead, I install them directly from my GitHub repo as follows:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>$ pipx install git+ssh://&lt;username&gt;@github.com/&lt;path-to-my-app.git&gt;
</span></span></code></pre></div><p>This method allows me to install Python applications quickly, and I can run each CLI application by simply typing <code>my_app_name</code> in the terminal.</p>
<p>The <code>pipx install</code> command is very flexible, and several switches are available. For example, the <code>--python</code> switch allows us to define which version of Python (v3.6+) to use for the installation, which can be very useful when trying different scenarios.</p>
<p>It&rsquo;s also possible to use the <code>pipx upgrade</code> to upgrade one&rsquo;s application. However, that assumes that one first has bumped the version number in GitHub. Instead, I rerun the <code>pip install</code> command with the <code>--force</code> switch, which doesn&rsquo;t care whether the version has been bumped.</p>
<p>Finally, I do not install my applications in &ldquo;editable&rdquo; mode (using the <code>-e</code> switch) on this Raspberry Pi as I do not edit code directly on this device.</p>
<h3 id="install-f451-pif451-package">Install <em>f451-piF451</em> package</h3>
<p>This package installs all custom applications and scripts for this Raspberry Pi device. There is currently only one application — <code>sysmon</code> — but others maybe added in the future.</p>
<p>When the <a href="https://github.com/mlanser/f451-piF451"><em>f451-piF451</em></a> package is intalled, the <code>sysmon</code> command is enabled and can be launched from the terminal as follows:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span><span style="color:#75715e"># == If installed with &#39;pip&#39; == </span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># -1- Run in current terminal session</span>
</span></span><span style="display:flex;"><span>$ sysmon --debug
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># -2- Run in background </span>
</span></span><span style="display:flex;"><span>$ nohup sysmon &gt; sysmon.out &amp;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># == If NOT installed with &#39;pip&#39; ==</span>
</span></span><span style="display:flex;"><span><span style="color:#75715e"># -3- Run in background </span>
</span></span><span style="display:flex;"><span>$ nohup python -u sysmon.py &gt; sysmon.out &amp;
</span></span></code></pre></div><p>The first command simply runs the <code>sysmon</code> application in &ldquo;debug&rsquo; mode in the current terminal session. This is a great way to test if your settings and the device are configured properly.</p>
<p>The second command launches the <code>sysmon</code> application in the background, and it will keep running even after the terminal window is closed. Any output will be redirected to the <code>sysmon.out</code> file.</p>
<p>Finally, the third command shows how to run <code>sysmon</code> in the background if the pacakage is not installed with <code>pip</code>.</p>


<div class="notices note" ><p>The <code>README.md</code> file for the <a href="https://github.com/mlanser/f451-piF451"><em>f451-piF451</em></a> package has further instructions on how to configure the <code>settings.toml</code> file, etc.</p></div>

<h2 id="summary">Summary</h2>
<p>Getting this Raspberry Pi up and running as a single-purpose device running a few CLI applications was trivial. However, it&rsquo;s worth noting that the goal is for this device to essentially never stop running. That means one needs to think through how to automate and streamline maintenance and support routines.</p>
<p>For example, from time to time, we&rsquo;ll need to update the OS, the various support libraries, etc. And, of course, every once in a while, we&rsquo;ll want to update the actual monitoring applications. Most maintenance tasks can be done without restarting the device. But there are occasions when the updates require a restart.</p>
<p>Finally, there are external events that may affect this device. For example, we had a day-long internet outage not too long ago, and when everything came back online, we had to restart the router. Then, there have been power outages in the neighborhood. And no, my home network of Raspberry Pis is not hosted in a data center with fail-over power, etc. So when the lights go out, the devices go down.</p>
<p>All this means that it&rsquo;s worth spending a bit of time creating easy (re-)start processes, upgrade scripts, and so on 😊</p>
]]>
      </content:encoded>
    </item>
    
    <item>
      <title>f451 Labs piRed - Collect Data With Sense HAT</title>
      <link>https://thinkinganalog.com/projects/f451-labs-pired/</link>
      <pubDate>Sat, 02 Dec 2023 00:00:00 +0000</pubDate>
      
      <guid>https://thinkinganalog.com/projects/f451-labs-pired/</guid>
      <description>
      
          
            
            
            <![CDATA[<img src="https://thinkinganalog.com/projects/f451-labs-pired/f451-piRED-sensemon-1200x800-min_hu_38a6be88646043.jpg" width="640" height="427"/><br>]]>
          
        
      <![CDATA[ The main objective of this project is to run one or more monitoring applications and display some form of progress on an onboard display.]]>
      </description>
      <content:encoded>
      
          
            
            
            <![CDATA[<img src="https://thinkinganalog.com/projects/f451-labs-pired/f451-piRED-sensemon-1200x800-min_hu_38a6be88646043.jpg" width="640" height="427"/><br>]]>
          
        
      <![CDATA[ <h2 id="overview">Overview</h2>
<p>The main objective of this project is to run one or more monitoring applications and display some form of progress on an onboard display. This <a href="https://raspberrypi.org">Raspberry Pi</a> has a <a href="https://www.raspberrypi.com/documentation/accessories/sense-hat.html">Raspberry Pi Sense HAT</a> with an 8x8 LED display, several onboard sensors, and a joystick.</p>
<p>I also have <a href="https://thinkinganalog.com/projects/f451-labs-pif451">another Rasberry Pi equipped with a Sense HAT</a>. But on that device we only use the onboard LED display to show real-time internet speed test data. And yes, I sometimes purchase more than one unit of this or that hardware because I have these grand plans of building crazy projects &hellip; but then I forget about the project and build something else instead.</p>
<p>I could blame this forgetfulness on old age. But instead, I will blame it on my day job interfering with my much-needed hobby time &hellip; there I said it! 🤓</p>
<p>Anyway, this particular Raspberry Pi device currently runs one application — <a href="https://thinkinganalog.com/projects/f451-labs-rpi-sensemon-app"><em>sensemon</em></a> — and the main task is to collect indoor environment data at regular intervals. However, since I already have <a href="https://thinkinganalog.com/projects/f451-labs-pienviro">another device with more accurate sensors</a>, the data from this device is not uploaded to the cloud. It does get displayed on the onboard 8x8 LED display, though.</p>
<p>Finally, the Sense HAT joystick can switch display modes to show different environment data, and there is also a &ldquo;Sparkle Mode,&rdquo; which is very pretty at night. It also lets me know that the app is still running 😊</p>
<h2 id="device-specifications--configuration">Device specifications &amp; configuration</h2>
<h3 id="general-specifications">General specifications</h3>
<p>I decided to use an older Raspberry Pi as there&rsquo;s not much needed to run the monitoring application. The device is headless and we&rsquo;re therefore running the OS without the GUI (desktop).</p>
<ul>
<li>Device: <a href="https://www.raspberrypi.com/products/raspberry-pi-3-model-b/">RP3</a> - Model B Rev 1.2 / 1GB - <a href="https://www.raspberrypi.com/software/operating-systems/#raspberry-pi-os-legacy">Bullseye (Debian 11)</a> / 32bit</li>
<li>Network: wlan0 (wifi)</li>
<li>Display &amp; keyboard: none</li>
<li>Other hardware: <a href="https://www.raspberrypi.com/documentation/accessories/sense-hat.html">Raspberry Pi Sense HAT</a></li>
<li>Remote access: SSH</li>
</ul>
<h3 id="main-tools--applications">Main tools &amp; applications</h3>
<p>Most software on this device focuses on running various Python applications. But I&rsquo;ve also added a few tools to make life easier when I need to debug stuff after things go sideways.</p>
<ul>
<li><strong><a href="https://networkmanager.dev/">NetworkManager</a></strong> — my default tool for managing network settings on my RPIs</li>
<li><strong><a href="https://help.ubuntu.com/community/UFW">UFW (firewall)</a></strong> — my default tool for managing firewall settings on my RPIs</li>
<li><strong><a href="https://htop.dev/">htop</a></strong> — my default process viewer/manager on my RPIs</li>
<li><strong>Misc. tools</strong> — e.g. <a href="https://pypa.github.io/pipx/">PIPX</a>, <a href="https://git-scm.com/">git</a>, etc.</li>
</ul>
<p>As a side note, most of my devices are configured in similar ways with (mostly) the same tools. And while some devices have GUIs, most do not, and I usually access all devices from my laptop via SSH.</p>
<h3 id="custom-applications--scripts">Custom applications &amp; scripts</h3>
<p>This Raspberry Pi is configured the following applications and scripts:</p>
<ul>
<li><strong>sensemon</strong> — this application collects indoor environment data from the Sense HAT sensors. However, the application is not configured to upload the data anywhere as I already have <a href="https://thinkinganalog.com/projects/f451-labs-pienviro">another device</a> with even better sensors doing just that. Still, the data from the <code>sensemon</code> application is displayed in real-time on the onboard 8x8 LED display.</li>
</ul>


<div class="notices note" ><p>The <a href="https://thinkinganalog.com/projects/f451-labs-rpi-sensemon-app"><em>sensemon</em> application</a> is installed as part of the overall <a href="https://github.com/mlanser/f451-piRED"><em>f451-piRED</em></a> package. You can run it directly from the terminal when the package is installed with the <code>pip</code> or <code>pipx</code> commands (see below for more info).</p></div>

<h2 id="common-workflows">Common workflows</h2>
<p>Given its role as a single-purpose monitoring device, there is essentially only one workflow (aside from maintaining the device itself): install and run monitoring applications.</p>
<p>My CLI applications can be installed via the <code>pip</code> command, so the workflow is straightforward. Although, I have switched to using the <code>pipx</code> command to ensure that whatever application I install does not &ldquo;pollute&rdquo; the Python environment on this Raspberry Pi device.</p>
<p>Now, one additional wrinkle is that my applications and packages are not hosted on PyPi. Instead, I install them directly from my GitHub repo as follows:</p>
<div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"><code class="language-bash" data-lang="bash"><span style="display:flex;"><span>$ pipx install git+ssh://&lt;username&gt;@github.com/&lt;path-to-my-app.git&gt;
</span></span></code></pre></div><p>This method allows me to install Python applications quickly, and I can run each CLI application by simply typing <code>my_app_name</code> in the terminal.</p>
<p>The <code>pipx install</code> command is very flexible, and several switches are available. For example, the <code>--python</code> switch allows us to define which version of Python (v3.6+) to use for the installation, which can be very useful when trying different scenarios.</p>
<p>It&rsquo;s also possible to use the <code>pipx upgrade</code> to upgrade one&rsquo;s application. However, that assumes that one first has bumped the version number in GitHub. Instead, I rerun the <code>pip install</code> command with the <code>--force</code> switch, which doesn&rsquo;t care whether the version has been bumped.</p>
<p>Finally, I do not install my applications in &ldquo;editable&rdquo; mode (using the <code>-e</code> switch) on this Raspberry Pi as I do not edit code directly on this device.</p>
<h2 id="summary">Summary</h2>
<p>Getting this Raspberry Pi up and running as a single-purpose device running a few CLI applications was trivial. However, as with some of my other single-purpose devices, the goal is (ideally) to never stop running. And yes, that&rsquo;s an impossible goal. Nevertheless, that&rsquo;s what we&rsquo;re working towards, which means one must think through how to automate and streamline maintenance and support routines.</p>
<p>For example, we&rsquo;ll need to update the OS and various support libraries over time. And, of course, every once in a while, we&rsquo;ll want to update the actual monitoring applications. Most maintenance tasks can be done without restarting the device. But there are occasions when the updates require a restart.</p>
<p>Finally, there are external events that may affect this device. For example, there&rsquo;s the occasional internet or power outage. In short, the devices go down when the proverbial (and very real) lights go out.</p>
<p>All this means that it&rsquo;s worth spending a bit of time creating easy (re-)start processes, upgrade scripts, and so on 😊</p>
]]>
      </content:encoded>
    </item>
    
  </channel>
</rss>
