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

<channel>
	<title>Programming Archives - ClickedyClick</title>
	<atom:link href="https://gergely.imreh.net/blog/category/comp/prog/feed/" rel="self" type="application/rss+xml" />
	<link>https://gergely.imreh.net/blog/category/comp/prog/</link>
	<description>Life in real, complex and digital.</description>
	<lastBuildDate>Thu, 30 Jan 2025 02:59:00 +0000</lastBuildDate>
	<language>en-GB</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	
	<item>
		<title>Refreshing Airplane Tracking Software With and Without AI</title>
		<link>https://gergely.imreh.net/blog/2025/01/refreshing-airplane-tracking-software-with-and-without-ai/</link>
					<comments>https://gergely.imreh.net/blog/2025/01/refreshing-airplane-tracking-software-with-and-without-ai/#respond</comments>
		
		<dc:creator><![CDATA[Gergely Imreh]]></dc:creator>
		<pubDate>Sun, 19 Jan 2025 06:13:59 +0000</pubDate>
				<category><![CDATA[Computers]]></category>
		<category><![CDATA[Machine Learning]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[ADS-B]]></category>
		<category><![CDATA[DVB-T]]></category>
		<category><![CDATA[SDR]]></category>
		<guid isPermaLink="false">https://gergely.imreh.net/blog/?p=2925</guid>

					<description><![CDATA[<p>Bug fixing with LLMs won't get you far if you don't speak the (programming) language, so better use your head.</p>
<p>The post <a href="https://gergely.imreh.net/blog/2025/01/refreshing-airplane-tracking-software-with-and-without-ai/">Refreshing Airplane Tracking Software With and Without AI</a> appeared first on <a href="https://gergely.imreh.net/blog">ClickedyClick</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>A bit like last time this post is about a bit of programmer hubris, a bit of AI, a bit of failure&#8230; Though I also took away more lessons this time about software engineering, with or without fancy tools. This is about rabbit-holing myself into an old software project that I had very little knowhow to go on&#8230;</p>



<p>The story starts with me rediscovering a <a href="https://en.wikipedia.org/wiki/DVB-T">DVB-T</a> receiver USB stick, that I had for probably close to decade. It&#8217;s been &#8220;barnacled&#8221; by time spent in the Taiwanese climate, so I wasn&#8217;t sure if it still works, but it&#8217;s such a versatile tool, that it was worth trying to revive it.</p>



<p>When these receivers function, they can receive digital TV (that&#8217;s the DVB-T), but also FM radio, DAB, and also they can act as software defined radio (SDR). This last thing makes them able to receive all kinds of transitions that are immediately quite high on the fun level, in particular airplane (ADS-B transmission) and ship (AIS) tracking. Naturally, there are websites to do both if you just want to see it (for example <a href="https://www.flightradar24.com">Flightradar24</a> and <a href="https://www.marinetraffic.com/">MarineTraffic</a>, respectively, are popular aggregators for that data but there are tons), but doing your own data collection opens doors to all kinds of other use cases.</p>



<p>So on I go, trying to find, what software tools people use these days to use these receivers. Mine is a pretty simple one (find out everything about it by following the &#8220;RTL-SDR&#8221; keywords wherever you like to do that :) and so I remembered there were many tools. However also time passed, I forgot most that I knew, and also there were new projects coming and going.</p>



<h2 class="wp-block-heading">ADSBox</h2>



<p>While I was searching, I found the <a href="https://github.com/netdisciple/adsbox">adsbox</a> project, that was interesting both kinda working straight out of box for me, while it was also last updated some 9 years ago, so it&#8217;s an old code base that tickles my &#8220;let&#8217;s maintain all the things!&#8221; drive&#8230;</p>



<figure class="wp-block-image size-large"><img fetchpriority="high" decoding="async" width="1024" height="336" src="https://gergely.imreh.net/blog/wp-content/uploads/2025/01/adsbox-1024x336.png" alt="The GitHub repo information of ADSBox, last commits overall have been 9 years ago, and there are very few of them." class="wp-image-2933" srcset="https://gergely.imreh.net/blog/wp-content/uploads/2025/01/adsbox-1024x336.png 1024w, https://gergely.imreh.net/blog/wp-content/uploads/2025/01/adsbox-500x164.png 500w, https://gergely.imreh.net/blog/wp-content/uploads/2025/01/adsbox-768x252.png 768w, https://gergely.imreh.net/blog/wp-content/uploads/2025/01/adsbox-1200x393.png 1200w, https://gergely.imreh.net/blog/wp-content/uploads/2025/01/adsbox.png 1269w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>The tool is written mostly in C, while it also hosts its own server for a web interface, for listing flights, and (back in the day) supporting things like Google Maps and Google Earth.</p>



<figure class="wp-block-image size-large"><img decoding="async" width="1024" height="491" src="https://gergely.imreh.net/blog/wp-content/uploads/2025/01/adsbox_frontend1-1024x491.png" alt="The ADSBox interface showing a bunch of airplane information." class="wp-image-2929" srcset="https://gergely.imreh.net/blog/wp-content/uploads/2025/01/adsbox_frontend1-1024x491.png 1024w, https://gergely.imreh.net/blog/wp-content/uploads/2025/01/adsbox_frontend1-500x240.png 500w, https://gergely.imreh.net/blog/wp-content/uploads/2025/01/adsbox_frontend1-768x368.png 768w, https://gergely.imreh.net/blog/wp-content/uploads/2025/01/adsbox_frontend1-1200x576.png 1200w, https://gergely.imreh.net/blog/wp-content/uploads/2025/01/adsbox_frontend1.png 1280w" sizes="(max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">The adsbox plane listing interface.</figcaption></figure>



<p>Both the Google Maps and Earth parts seem completely: Maps has changed a lot since, as I also had to update my <a href="https://gergely.imreh.net/blog/2015/11/taiwan-wwii-map-overlays/">Taiwan WWII Map Overlays</a> project over time too (the requirement of using API keys to even load the map, changes to the JavaScript API&#8230;). Earth I haven&#8217;t tried, but I&#8217;m thinking that went the way of the dodo on the the desktop?</p>



<span id="more-2925"></span>



<p>So in the supur of the this-is-the-weekend-and-I-have-energy-to-code moment, I started to think of the options:</p>



<ul class="wp-block-list">
<li>could fix up the map, either with the Google Maps changes, or bring in some other map?</li>



<li>the project has barely any readme, and I mainly managed to make it work by looking at <a href="https://www.rtl-sdr.com/adsbox-new-ads-b-decoding-software-for-linux/">old articles from the time when <code>adsbox</code> waas new</a>, could fix those up?</li>



<li>during the compilation, loads of warnings happened, that seem to call for some &#8220;better quality&#8221; coding, let&#8217;s fix stuff until <code>-Werror</code> (making all warnings errors) passes too! This would be a learning experience</li>



<li>I&#8217;m sure I can find other tasks to do as well, like an error message here, a strange behaviour there&#8230;</li>
</ul>



<p>Here&#8217;s the kicker though: I don&#8217;t really know C. I spend most of my time in Python-land, and haven&#8217;t done a C project in anger yet. Is it worth trying to dig in, while there are other ADS-B projects that a) work better, b) are in languages that I&#8217;m more looking to learn, such as Rust?</p>



<p>There was an additional drive of curiosity, just like in my last post: <em>can I use Large Language Models (LLMs) to complement me on things I lack, such as knowledge of the exact programming language at hand?</em></p>



<p>With this I thought let&#8217;s dig in, and let&#8217;s dig into the C code: that seemed immediately tractable, more limited in scope, and thus would help build up (hopefully) some successes and I&#8217;ll learn my way around the codebase better.</p>



<p>On the LLM side I have <a href="https://github.com/features/copilot">GitHub Copilot</a> &#8211; though it seems somewhat crippled in my open source <a href="https://github.com/coder/code-server">Code Server</a> installation of VS Code, rather than the official VS Code, in particular the context menus and Copilot Chat seems missing, and thus it was only communicating with me through TAB-completions and me adding comments to guide or suggest. That&#8217;s not very practical, so didn&#8217;t push it too far for the relevant tasks of explanation and exploration of options that I wanted to do.</p>



<p>I also have <a href="https://claude.ai/">Claude</a> that I can chat with. If I wasn&#8217;t working on my 13 year old <a href="https://en.wikipedia.org/wiki/ThinkPad_X_series">Lenovo ThinkPad X201</a>, I&#8217;d probably set up <a href="https://ollama.com/">Ollama</a>, but that&#8217;s just excruciating with even the smallest models on this machine (until I upgrade something newer, or run the questions on my work M1 MacBook). So Claude it is for now.</p>



<h3 class="wp-block-heading">Hello Fixes</h3>



<p>I guess it&#8217;s one sign of hubris (or unlimited optimism), to jump into fixing compilation warnings, without knowing anything much of the codebase yet. This started in areas where the airplane tracking interacts with <a href="https://www.sqlite.org/index.html">SQLite</a>, for example had warnings about <strong>casting pointers to integers of different size</strong> while shuffling around SQLite query results:</p>



<pre class="wp-block-code"><code class="">int * t = (int *) sqlite3_value_int(argv[0]);</code></pre>



<p>This was also part of a larger code section (formatting integers into hexadecimal or octal strings, for example for the ICAO codes&#8230;), and thus had to play around how much context to give to Claude to actually have something useful.</p>



<figure class="wp-block-image size-full"><img decoding="async" width="740" height="509" src="https://gergely.imreh.net/blog/wp-content/uploads/2025/01/adsbox_claude.png" alt="Chatting with Claude about the code snippet, my question and their answer shown in part." class="wp-image-2928" srcset="https://gergely.imreh.net/blog/wp-content/uploads/2025/01/adsbox_claude.png 740w, https://gergely.imreh.net/blog/wp-content/uploads/2025/01/adsbox_claude-500x344.png 500w" sizes="(max-width: 740px) 100vw, 740px" /><figcaption class="wp-element-caption">A segment from a discussion with Claude.</figcaption></figure>



<p>A bit of mocking around there seemed to have worked, and while I should have asked more software architecture &amp; best practices questions, probably knew about it enough to be dangerous, and left it as it was so far.</p>



<p>Having said that, after this change it turned out that some part of the interface now displaying stuff differently: the 24-bit ICAO airplane registration codes had useless leading zeros for 8 hex digits, rather than the expected 6 digits &#8211; since the fix was done without this context. Here we go, manual adaptation on this regression.</p>



<p>Now there were cases when &#8220;<strong>sprintf may write a terminating nul past the end of the destination</strong>&#8220;, as the code seems to have written its data back into the same place as this:</p>



<pre class="wp-block-code"><code class="">sprintf(data-&gt;avr_data, "*%s", data-&gt;avr_data + 13);</code></pre>



<p>This ended up being again about a much bigger context (interative reading, processing, and passing on of recorded ADS-B packets), where based on the Claude&#8217;s suggestions I couldn&#8217;t really get to anything useful. The real point was always one step further:</p>



<ul class="wp-block-list">
<li>instead of the line look at the nearby lines</li>



<li>instead of the near by lines, look at the whole funciton</li>



<li>instead of the whole function, look at the wider codebase with its configuration</li>
</ul>



<p>These are of course no-brainers. However Claude with its chat interface cannot really do that, while Copilot without its chat interface also cannot do this digging. Catch-22? Since in the end I admitted myself (for the <em>n</em>th time) that I need to understand the purpose of the code better before &#8220;fixing&#8221; it. Then due to the lack of comments in the codebase + lack of natural intuition of the built in C functions&#8217; behaviour, I&#8217;ve just left them as they were for now, since they do work.</p>



<p>From here I turned to other parts. The <strong>webserver was not serving some files with the correct MIME type</strong>, due to its hand-rolled file extension extraction (splitting filenames at the first <code>.</code> rather than the last), this was easy to fix &#8211; with a bit of StackOverflow this time, rather than asking Claude.</p>



<p>Then there was an issue with <strong>the tool apparently not playing back the recorded packet data</strong>, which I fixed with a combo of regular ol&#8217; debug printouts, StackOverflow, and just thinking about how it could work (it&#8217;s the issue of explicitly filling in daylight saving data in the relevant <code>tm</code> struct &#8211; <code>tm_isdst</code> &#8211; and thus IMHO it&#8217;s doing a regular &#8220;undefined&#8221; behaviour: in this case jumped the first timestamp&#8217;s time ahead by an hour, and thus would have needed to wait an hour to pass as the playback (following the real timingof the packets) catch up and start actually replaying. Still weird, why only the first packet&#8217;s data was shifted, and could I do a more solid fix than setting it once as the code never seem to overwrite it? These are the questions that are more addressing C-knowledge or potential best practice of the code&#8217;s structure overall&#8230;</p>



<p>Finally I&#8217;ve started on <strong>replacing Google Maps</strong> with <a href="https://openfreemap.org/">OpenFreeMap</a> and got as far as displaying the map (which is the easy step:). The whole replacement would likely be a lot more, also given the amount of barely documented JavaScript code in the project &#8211; but hopefully I have more working knowledge of JS than C.</p>



<h3 class="wp-block-heading">Lessons Learned</h3>



<p>First lesson is that I likely have a &#8220;saviour complex&#8221;, trying to fix up every code I see being imperferct in some way, whether or not I am capable of doing it or not. This is something to meditate further on for sure.</p>



<p>When using LLMs for code work, they are just as useful as another mid-level coder without much context &#8211; almost not at all. The context of code is <em>always</em> relevant, so either the LLM would have to get it itself, or the person pairing with the LLM would have to provide it. Thus the work is always there, just not always possible.</p>



<p>It&#8217;s very nice that I can do things in programming languages that I don&#8217;t really understand, but that&#8217;s only the case if I either spend much-much time actually getting to know things so I can start to judge whether the changes even have a chance to be correct or not; or I don&#8217;t care whether they are correct or not (but is this really an option?)</p>



<p>Overall the LLMs need the same things as humans to do a good job, and cannot pretend that they really can do work without these (even if they might appear being able to do without these for some time):</p>



<ul class="wp-block-list">
<li>good comment in the code so the intention can be ascertained as well</li>



<li>tests that show what the correct behaviour should be, and catch regressions or unintentional breakages</li>



<li>have domain knowledge to form better mental models about what should happen</li>
</ul>



<p>The first two wasn&#8217;t true in this project. The last point is likely where LLMs are ahead in cases like this (having been trained on &#8220;all the Internet&#8217;s data&#8221;), though wouldn&#8217;t be the same for some niche, or work internal projects.</p>



<p>The LLMs suggestions are still ver much localised, thus they cannot really fix up the structure of the code too much &#8211; or maybe I&#8217;m not using the right tools, of course. And this is where my future big ask would lie: don&#8217;t just tell me how to fix this line, rather tell me that the entire block is no longer needed / could be merged with another part of the code / could be broken out to its own module that would help over there&#8230; Of course, this is moving the goal post a bit of what LLM programmers&#8217; look like, though I also think that the current &#8220;fix this line&#8221; is something I most definitely want to have enough practice with that I don&#8217;t really need to ask (though it could suggest if there are good practices I haven&#8217;t picked up yet).</p>



<h2 class="wp-block-heading">Where do I go from here?</h2>



<p>This adsbox project is mostly obsolete, as I&#8217;ve found a bunch of other tools that are better, and better supported now (<a href="https://github.com/rsadsb/adsb_deku">adsb_deku</a>, <a href="https://github.com/wiedehopf/tar1090">tar1090</a>), but surprising it still have stuff that are better here and in other tools (the plane&#8217;s status icons, some data displayed here that is not in others, showing what sort of packets (what Downlink Format or DF numbers) were received for the aircraft, etc&#8230; So there might be still value in using it occasionally, so there might be value. </p>



<p>Even if I could get a kick out of it, it&#8217;s likely useful to keep things time-boxed or constrained to some topics: change the map; add comments as I find them; fix issues if they arise; package it up for ArchLinux. That&#8217;s about it, but these should be generally useful (e.g. using OpenFreeMap for other projets in the future or rewriting the aforementioned <a href="https://imrehg.github.io/taiwanmap/">Taiwan WWII Map project</a> to use that).</p>



<p>My current fixes live in my fork in GitHub <a href="https://github.com/imrehg/adsbox">imrehg/adsbox</a>, with no guarantees. Since the project also doesn&#8217;t have a license (just a note of &#8220;free for non-commercial use&#8221;, which doesn&#8217;t cover modifications), I&#8217;m probably keeping it simple for now.</p>



<p>I also got the hang of software defined radio again, and there&#8217;s just so much fun to have&#8230;</p>



<p>What&#8217;s the most useful is seeing in practice, what does software need to be maintainable almost a decade later, and what&#8217;s missing in most projects: explanatory comments to understand what is being done and why, and tests to know whether things are running correctly or not. And maube then both my future self, my colleagues, and any potential AI pair programmer would have a better chance of succeeding at &#8220;maintain all the things!&#8221;</p>
<p>The post <a href="https://gergely.imreh.net/blog/2025/01/refreshing-airplane-tracking-software-with-and-without-ai/">Refreshing Airplane Tracking Software With and Without AI</a> appeared first on <a href="https://gergely.imreh.net/blog">ClickedyClick</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://gergely.imreh.net/blog/2025/01/refreshing-airplane-tracking-software-with-and-without-ai/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Adventures into Code Age with an LLM</title>
		<link>https://gergely.imreh.net/blog/2024/11/adventures-into-code-age-with-an-llm/</link>
					<comments>https://gergely.imreh.net/blog/2024/11/adventures-into-code-age-with-an-llm/#respond</comments>
		
		<dc:creator><![CDATA[Gergely Imreh]]></dc:creator>
		<pubDate>Sat, 09 Nov 2024 09:50:20 +0000</pubDate>
				<category><![CDATA[Computers]]></category>
		<category><![CDATA[Machine Learning]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Claude]]></category>
		<category><![CDATA[llm]]></category>
		<category><![CDATA[python]]></category>
		<guid isPermaLink="false">https://gergely.imreh.net/blog/?p=2910</guid>

					<description><![CDATA[<p>It&#8217;s a relaxed Saturday afternoon, and I just remembered some nerdy plots I&#8217;ve seen online for various projects, depicting &#8220;code age&#8221; over time: how does your repository change over the months and years, how much code still survives from the beginning till now, etc&#8230; Something like this made by the author of curl: It looks [&#8230;]</p>
<p>The post <a href="https://gergely.imreh.net/blog/2024/11/adventures-into-code-age-with-an-llm/">Adventures into Code Age with an LLM</a> appeared first on <a href="https://gergely.imreh.net/blog">ClickedyClick</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>It&#8217;s a relaxed Saturday afternoon, and I just remembered some nerdy plots I&#8217;ve seen online for various projects, depicting &#8220;code age&#8221; over time: how does your repository change over the months and years, how much code still survives from the beginning till now, etc&#8230; Something like <a href="https://daniel.haxx.se/blog/2024/10/31/curl-source-code-age/">this made by the author of curl</a>:</p>



<figure class="wp-block-image size-large is-style-default"><img loading="lazy" decoding="async" width="1024" height="644" src="https://gergely.imreh.net/blog/wp-content/uploads/2024/11/screenshot-2024-10-31-at-13-39-29-gnuplot-1024x644.png" alt="" class="wp-image-2914" srcset="https://gergely.imreh.net/blog/wp-content/uploads/2024/11/screenshot-2024-10-31-at-13-39-29-gnuplot-1024x644.png 1024w, https://gergely.imreh.net/blog/wp-content/uploads/2024/11/screenshot-2024-10-31-at-13-39-29-gnuplot-500x314.png 500w, https://gergely.imreh.net/blog/wp-content/uploads/2024/11/screenshot-2024-10-31-at-13-39-29-gnuplot-768x483.png 768w, https://gergely.imreh.net/blog/wp-content/uploads/2024/11/screenshot-2024-10-31-at-13-39-29-gnuplot-1536x966.png 1536w, https://gergely.imreh.net/blog/wp-content/uploads/2024/11/screenshot-2024-10-31-at-13-39-29-gnuplot-2048x1288.png 2048w, https://gergely.imreh.net/blog/wp-content/uploads/2024/11/screenshot-2024-10-31-at-13-39-29-gnuplot-1200x754.png 1200w, https://gergely.imreh.net/blog/wp-content/uploads/2024/11/screenshot-2024-10-31-at-13-39-29-gnuplot-1980x1245.png 1980w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">Curl&#8217;s code age distribution</figcaption></figure>



<p>It looks interesting and informative. And even though I don&#8217;t have codebases that have been around this long, there are plenty of codebases around me that are fast moving, so something like a month (or in some cases week) level cohorts could be interesting.</p>



<p>One way to take this challenge on is to actually sit down and write the code. Another is to take a <a href="https://en.wikipedia.org/wiki/Large_language_model">Large Language Model</a>, say <a href="https://claude.ai/">Claude</a> and try to get that to make it. Of course the challenge is different in nature. For this case, let&#8217;s put myself in the shoes of someone who says</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>I am more interested in the results than the process, and want to get to the results quicker.</p>
</blockquote>



<p>See how far we can get with this attitude, and where does it break down (probably no spoiler: it breaks down very quickly.).</p>



<p>Note on the selection of the model: I&#8217;ve chosen Claude just because generally I have good experience with it these days, and it can share generated artefacts (like the relevant Python code) which is nice. And it&#8217;s a short afternoon. :) Otherwise anything else could work as well, though surely with varying results. </p>



<h3 class="wp-block-heading">Version 1</h3>



<p>Let&#8217;s kick it off with a quick prompt.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><strong>Prompt</strong>: How would you generate a chart from a git repository to show the age of the code? That is when the code was written and how much of it survives over time?</p>
</blockquote>



<p>Claude quickly picked it up and made me a Python script, which is nice (that being my day-to-day programming language). I guess that&#8217;s generally a good assumption these days if one does data analytics anyways (asking for another language is left for another experiment).</p>



<span id="more-2910"></span>



<p>The result is this <a href="https://claude.site/artifacts/d7c4b1f6-e6c4-4d74-82dd-97e0d40d0c5e">this code</a>. I&#8217;ve skimmed it that it doesn&#8217;t just delete all my repo or does something completely batshit, but otherwise saved in a repo that I have at hand. To make it easier on myself, added some <a href="https://packaging.python.org/en/latest/specifications/inline-script-metadata/#inline-script-metadata">inline metadata</a> with the dependencies:</p>



<pre class="wp-block-code"><code class=""># /// script
# dependencies = [
#   "pandas",
#   "matplotlib",
# ]
# ///</code></pre>



<p>and from there I can just run the script with <a href="https://docs.astral.sh/uv/">uv</a>.</p>



<p>First it checked too few files (my repository is a mixture of Python and SQL scripts managed by <a href="https://www.getdbt.com/">dbt</a>), so had to go in and change those filters, expanding them.</p>



<p>Then the thought struck me to remove the filter altogether (since it already checks only files that are checked in git, so it should be fine &#8211; but then it broke on a step where it reads a file as if it was text to find the line counts. I guess there could be a better way of filtering (say &#8220;do not read binary files&#8221;, if there&#8217;s a way to do that), but just went with catching the problems:</p>



<pre class="wp-block-code"><code class=""># ....
    for file_path in tracked_files:
        try:
            timestamps = get_file_blame_data(file_path)
            for timestamp in timestamps:
                blame_data[timestamp] += 1
                total_lines += 1
        except UnicodeDecodeError:
            print(f"Error reading file: {file_path}")
            continue
#....</code></pre>



<p>(hance I know that a favicon PNG was causting those <code>UnicodeDecodeError</code> hubbub in earlier runs. Now we are getting somewhere, and we have a graph like this:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="512" src="https://gergely.imreh.net/blog/wp-content/uploads/2024/11/code_age_distribution-1024x512.png" alt="" class="wp-image-2911" srcset="https://gergely.imreh.net/blog/wp-content/uploads/2024/11/code_age_distribution-1024x512.png 1024w, https://gergely.imreh.net/blog/wp-content/uploads/2024/11/code_age_distribution-500x250.png 500w, https://gergely.imreh.net/blog/wp-content/uploads/2024/11/code_age_distribution-768x384.png 768w, https://gergely.imreh.net/blog/wp-content/uploads/2024/11/code_age_distribution.png 1200w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">Version 1</figcaption></figure>



<p>This is already quite fun to see. There are the sudden accelerations of development, there are the plateaus of me working on other projects, and generally feel like &#8220;wow, productive!&#8221; (with no facts backing that feeling <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f602.png" alt="😂" class="wp-smiley" style="height: 1em; max-height: 1em;" />). Also pretty good ROI on maybe 15 mins of effort.</p>



<p>Having said that, this is still fair from what I wanted.</p>



<h3 class="wp-block-heading">Version 2</h3>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><strong>Promt:</strong> Could we change the code to have cohorts of time, that is configurable, say monthly, or yearly cohoorts, and colour the chart to see how long each cohort survives?</p>
</blockquote>



<p>This came back with another <a href="https://claude.site/artifacts/34b65023-9ba4-4abb-b214-1c10d82eacfd">set of code</a>. Adding the metadata, skimming it (it has the filter on the file extensions again, never mind), and running it once more to see the output, I get this:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="542" src="https://gergely.imreh.net/blog/wp-content/uploads/2024/11/code_survival_monthly-1024x542.png" alt="" class="wp-image-2912" srcset="https://gergely.imreh.net/blog/wp-content/uploads/2024/11/code_survival_monthly-1024x542.png 1024w, https://gergely.imreh.net/blog/wp-content/uploads/2024/11/code_survival_monthly-500x265.png 500w, https://gergely.imreh.net/blog/wp-content/uploads/2024/11/code_survival_monthly-768x406.png 768w, https://gergely.imreh.net/blog/wp-content/uploads/2024/11/code_survival_monthly-1536x813.png 1536w, https://gergely.imreh.net/blog/wp-content/uploads/2024/11/code_survival_monthly-2048x1083.png 2048w, https://gergely.imreh.net/blog/wp-content/uploads/2024/11/code_survival_monthly-1200x635.png 1200w, https://gergely.imreh.net/blog/wp-content/uploads/2024/11/code_survival_monthly-1980x1048.png 1980w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">Version 2</figcaption></figure>



<p>Because of the file extension filter in place, the numbers are obviously not aligning with the above, but it does something. The something is a bit unclear, bit it <em>feels</em> like progress, so let&#8217;s give it a benefit of the doubt, and just change once more. </p>



<h3 class="wp-block-heading">Version 3</h3>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p><strong>Promt:</strong> Now change this into a cummulative graph, please.</p>
</blockquote>



<p>One more time Claude came back with <a href="https://claude.site/artifacts/a391c5dc-743c-439f-aa09-70ec9b86a19a">this code</a>. Adding the metadata again, same drill. Running this has failed with errors in <code>numpy</code>, though:</p>



<pre class="wp-block-code"><code class="">TypeError: ufunc 'isfinite' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''</code></pre>



<p>Now this needed some debugging. It turns out a column the code is trying to plot is actually numbers as strings rather than numbers as, you know, say floats&#8230;</p>



<pre class="wp-block-code"><code class=""># my "fix"
        df['cumulative_percentage'] = df['cumulative_percentage'].astype(float)
# end

        # Plot cumulative area
        plt.fill_between(df.index, df['cumulative_percentage'],
                        alpha=0.6, color='royalblue',
                        label='Cumulative Code')</code></pre>



<p>It didn&#8217;t take too many tries, but it was confusing at first &#8211; why shouldn&#8217;t be, if I didn&#8217;t actually <em>read</em> just skim the code&#8230;</p>



<p>The result is then like this:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="543" src="https://gergely.imreh.net/blog/wp-content/uploads/2024/11/code_growth_monthly-1024x543.png" alt="" class="wp-image-2913" srcset="https://gergely.imreh.net/blog/wp-content/uploads/2024/11/code_growth_monthly-1024x543.png 1024w, https://gergely.imreh.net/blog/wp-content/uploads/2024/11/code_growth_monthly-500x265.png 500w, https://gergely.imreh.net/blog/wp-content/uploads/2024/11/code_growth_monthly-768x407.png 768w, https://gergely.imreh.net/blog/wp-content/uploads/2024/11/code_growth_monthly-1536x814.png 1536w, https://gergely.imreh.net/blog/wp-content/uploads/2024/11/code_growth_monthly-2048x1085.png 2048w, https://gergely.imreh.net/blog/wp-content/uploads/2024/11/code_growth_monthly-1200x636.png 1200w, https://gergely.imreh.net/blog/wp-content/uploads/2024/11/code_growth_monthly-1980x1049.png 1980w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">Version 3</figcaption></figure>



<p>Sort of <em>meh</em>, it feels like it&#8217;s not going to the right direction overall.</p>



<p>But while debugging the above issues, I first tried tried to ask Claude about the error (maybe it can fix it itself), but came back with &#8220;Your message exceeds the <a href="https://support.anthropic.com/en/articles/7996848-how-large-is-claude-s-context-window">length limit</a>. &#8230;&#8221; (for free users, that is). So I kinda stopped here for the time being.</p>



<h2 class="wp-block-heading">Lessons learned</h2>



<p>The first lesson is very much re-learned:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Garbage in, garbage out.</p>
</blockquote>



<p>If I cannot express what I really want, it&#8217;s very difficult to make it happen. And my prompts were by no means expressing my wishes correctly, no wonder Claude wasn&#8217;t really hitting the mark. Whether or not a human engineer would have faired better, I don&#8217;t know. I know however, that this kind of &#8220;tell me exceedingly clearly what&#8217;s your idea&#8221; is an everyday conversation for me as an engineer (and being on both end of the convo).</p>



<p>The code provided by the model wasn&#8217;t really far off for <em>some</em> solution, so that was fun! On the other hand, when it hit any issues, I really had to have domain and language knowledge to fix things. This seems like an interesting place to be:</p>



<ul class="wp-block-list">
<li>the results are quick and on the surface good-enough for a non/less technical person, probably</li>



<li>but they would also be the ones who couldn&#8217;t do anything if something goes wrong.</li>
</ul>



<p>Even myself I feel that it would be hard to support the code as a software engineer if it was just generated like this. But that&#8217;s also a strange thought: so many times I have to support (debug, extend, explain, refactor) code that I haven&#8217;t had anything to do with before.</p>



<p>It seems to me that now that since Claude comes across as an eager junior engineer, writing decent code that always needs some adjustments, the trade-off is really in the dimension of spending time to get better at prompting vs better at coding. </p>



<p>If there&#8217;s a person with some amount of programming skills, mostly interested in the results not the process, and doubling down on prompting: they likely could get loads further than I did here. Good quality prompts and small amount of code adjustments being the sweet spot for them.</p>



<p>For others who have more programming expertise, and maybe more interested in the process, spending time on getting better at programming rather than getting really better at prompting: keeping to smaller snippets might be the sweet spot, or learning new languages, &#8230; Something as a starting point for digging in, a seed, is what this process can help with.</p>



<h2 class="wp-block-heading">Future</h2>



<p>Given the above notes on how this generated code is like a new codebase that I suddenly neet to support, here&#8217;s a different, fun exercise <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> to actually improve engineering skills:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Take AI generated code that is &#8220;good enough&#8221; for a small problem and refactor, extent, productionise it.</p>
</blockquote>



<p>I&#8217;m not sure if this would work, or would get me into wrong habits, but if I wanted do have some quick ways of doing <a href="https://en.wikipedia.org/wiki/Peak:_Secrets_from_the_New_Science_of_Expertise">deliberate practice</a> &#8211; and not <a href="https://exercism.org/">Exercism</a>, <a href="https://gergely.imreh.net/blog/2023/08/doing-the-easy-problems-on-leetcode/">LeetCode</a>, or somilar, rather something that can be custom made, then this seems a way to get started.</p>



<p>Also, now that I&#8217;ve gotten even more interested in the problem, I&#8217;ll likely just dig into how to actually define that chart I was looking for and what kind of data I would need to get from <code>git</code> to make it happen. The example code made me pretty confident, that &#8220;all I need is Python&#8221; really, even though while prepping for this I found other useful tools like <a href="https://github.com/mergestat/mergestat-lite">one allowing you to write SQL queries for your repo</a>, that might be some further way to expand my understanding.</p>



<p>Either way, it&#8217;s just fun to mess with code on a lazy Saturday.</p>
<p>The post <a href="https://gergely.imreh.net/blog/2024/11/adventures-into-code-age-with-an-llm/">Adventures into Code Age with an LLM</a> appeared first on <a href="https://gergely.imreh.net/blog">ClickedyClick</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://gergely.imreh.net/blog/2024/11/adventures-into-code-age-with-an-llm/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Making a USB Mute Button for Online Meetings</title>
		<link>https://gergely.imreh.net/blog/2023/08/making-a-usb-mute-button-for-online-meetings/</link>
					<comments>https://gergely.imreh.net/blog/2023/08/making-a-usb-mute-button-for-online-meetings/#comments</comments>
		
		<dc:creator><![CDATA[Gergely Imreh]]></dc:creator>
		<pubDate>Sat, 19 Aug 2023 04:28:00 +0000</pubDate>
				<category><![CDATA[Maker]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[arduino]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[Seeed Studio]]></category>
		<category><![CDATA[USB]]></category>
		<category><![CDATA[USB HID]]></category>
		<guid isPermaLink="false">https://gergely.imreh.net/blog/?p=2801</guid>

					<description><![CDATA[<p>Since Google Meet teases us to add a USB device to controll calls, let's learn how to teach an Arduino clone to act like a phone mute button, and thus ultimately being capable to act like an infinite variety of peripheral devices.</p>
<p>The post <a href="https://gergely.imreh.net/blog/2023/08/making-a-usb-mute-button-for-online-meetings/">Making a USB Mute Button for Online Meetings</a> appeared first on <a href="https://gergely.imreh.net/blog">ClickedyClick</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>I use Google Meet every day for (potentially hours of) online meetings at work, so it&#8217;s very easy to notice when things change and for example new features are available. Recently I&#8217;ve found a new &#8220;Call Control&#8221; section in the settings that promised a lot of fun, <a href="https://support.google.com/meet/answer/12562325?hl=en">connecting USB devices to control my calls</a>.</p>



<figure class="wp-block-image size-full is-style-default"><img decoding="async" src="https://gergely.imreh.net/blog/wp-content/uploads/2023/08/Screenshot-2023-08-19-at-07.05.34.png" alt="Screenshot of the Google Meet Settings menu during calls, showing the call control menu and a call-out to connect my USB device." class="wp-image-2803"/><figcaption class="wp-element-caption">Google Meet Settings menu during a call, witht the Call control section</figcaption></figure>



<p>As someone who enjoys (or drawn to, or sort-of obscessed with) <a href="https://gergely.imreh.net/blog/category/maker/">hacking on hardware</a>, this was a nice call of action: let&#8217;s cobble together a custom USB button that can do some kind of call control<sup data-fn="7509dd7d-2867-4955-808e-d9bd3a9e8cd4" class="fn"><a href="#7509dd7d-2867-4955-808e-d9bd3a9e8cd4" id="7509dd7d-2867-4955-808e-d9bd3a9e8cd4-link">1</a></sup>: say muting myself in the call, showing mute status, hanging up, etc.</p>



<p>This kicked off such a deep rabbit hole that I barely made it back up to the top, but one that seeded a crazy amount of future opportunities. </p>



<span id="more-2801"></span>



<p>And as a shortcut, there&#8217;s a <a href="#demo">demo</a> below to showcase where I got to.</p>



<h2 class="wp-block-heading">Finding suitable hardware</h2>



<p>This step was harder than I&#8217;ve expected, given that I have drawers and drawers of gadgets, but I&#8217;m likely a bit out of practice, and also out of date. What I was looking for is</p>



<ul class="wp-block-list">
<li>Being able to show up as a USB device (must)</li>



<li>Have built in button (optional) or easy connectivity of buttons without breadboard for now</li>



<li>Have built in LED (optional) or some other way of showing 1 bit of information</li>
</ul>



<p>This doesn&#8217;t sound hard, right?</p>



<h3 class="wp-block-heading">ReSpeaker</h3>



<p>The first option that came up was Seeed Studio&#8217;s <a href="https://wiki.seeedstudio.com/ReSpeaker_Core/">ReSpeaker Core</a> that I had two of at hand: Arduino Leonardo compatibility, touch sensors for buttons, and an LED ring (the &#8220;Pixel Ring&#8221;). Turns out that they have been <em>discontinued</em> &#8211; which should be fine for now; but also my models are two different <em>pre-release prototypes</em> Seeed gave away for testers. Thus they are not quite like the final version, have different hardware on board here and there, so an experimental experience is expected.</p>



<figure class="wp-block-image size-large"><img decoding="async" src="https://gergely.imreh.net/blog/wp-content/uploads/2023/08/respeaker_core_prototypes-1024x572.jpg" alt="Photo of two ReSpeaker Core boards" class="wp-image-2809"/><figcaption class="wp-element-caption">ReSpeaker core samples to work with</figcaption></figure>



<p>The earlier prototype only has touch sensors on one side, the pixel ring lights up, but I couldn&#8217;t control it with <a href="https://github.com/respeaker/respeaker_arduino_library">Seeed&#8217;s ReSpeaker Arduino library</a>. The later prototype has two sides of sensors (effectively two buttons), but the lights don&#8217;t seem to work<sup data-fn="17ce950a-5b32-45de-8a5c-2464146a1840" class="fn"><a href="#17ce950a-5b32-45de-8a5c-2464146a1840" id="17ce950a-5b32-45de-8a5c-2464146a1840-link">2</a></sup>. Regardless this </p>



<h3 class="wp-block-heading">Aside: alternatives considered</h3>



<p>It was illuminating to see how much abandoned, obsolete, discontinued, or not quite useful hardware boards do I have.</p>



<p>One is RFDuino, that I got from <a href="https://www.kickstarter.com/projects/1608192864/rfduino-iphone-bluetooth-40-arduino-compatible-boa/">Kickstarter</a>, I&#8217;m yet to use, and all the project&#8217;s websites have already disappeared &#8211; fortunately not the <a href="https://github.com/RFduino/RFduino">code repo</a>. This would have been a more complex solution anyways, but wireless! Use one RFDuino to expose a USB Telephony device, and communicate wirelessly to another that operates the light and button on battery. Pretty cool. Also, it might not have worked if the chip used cannot do the cruicial &#8220;expose a USB [device]&#8221; part of the plan.</p>



<p>Other option that popped up was an <a href="https://store.arduino.cc/products/arduino-nano">Arduino Nano</a> + my own made <a href="https://www.tindie.com/products/imrehg/grovehat-for-arduino-nano/">GroveHat</a> + a <a href="https://wiki.seeedstudio.com/Grove-Button/">Grove Button</a>. Except, the Nano definitely cannot be a custom USB device, so there goes nothing.</p>



<p>Besides these, I&#8217;ve found plenty of:</p>



<ul class="wp-block-list">
<li>single board computers (old or obsolete),</li>



<li>FPGAs (never used, and would be a whole different project to implement something on them), and </li>



<li>other microcontrollers that all have interesting specialties, but don&#8217;t tick the mandatory boxes&#8230;</li>
</ul>



<p>These boards might not be right for now, but definitely there are projects in store for them (if only thre&#8217;s time).</p>



<p>Back to ReSpeaker then&#8230;</p>



<h2 class="wp-block-heading">Plugging in the USB</h2>



<p>The next thing is to figure out what&#8217;s really happening when an USB device is plugged in and it shows the operating system that it can do certain things. That is, how does Meet know that there&#8217;s a compatible device to connect to?</p>



<h3 class="wp-block-heading">The USB HID docs</h3>



<p>This is answered by the <a href="https://www.usb.org/hid">USB Human Interface Devices (HID)</a> specs &#8212; one that is pretty complicated, has a lot of legacy bits, and need a different kind of mindset. In a nutshell, though, with my current, partial understanding:</p>



<p>On connection the device sends a &#8220;report&#8221; to the OS that details on what can it do, including:</p>



<ul class="wp-block-list">
<li>what kind (or kinds!) of device it is?</li>



<li>what functionality of the kind is available in this particular implementation?</li>



<li>what&#8217;s the data layout to pass control information back-and-forth for this implementation?</li>
</ul>



<p>In our example, a very minimal setup would would be:</p>



<ul class="wp-block-list">
<li>I&#8217;m a Telephony Device (Usage page <code>0x0B</code>)</li>



<li>I implement a generic &#8220;Phone&#8221; (Usage ID <code>0x01</code>)</li>



<li>I have capability to do a &#8220;Phone Mute&#8221; (Usage ID <code>0x2F</code>)</li>



<li>Here&#8217;s the 1 bit of a 1 byte payload that conveys that phone mute status</li>
</ul>



<figure class="wp-block-image size-large"><img decoding="async" src="https://gergely.imreh.net/blog/wp-content/uploads/2023/08/Screenshot-2023-08-19-at-07.55.31-1024x920.png" alt="Screenshot of the beginning of the Telephony Device section from the HID Usage Tables" class="wp-image-2808"/><figcaption class="wp-element-caption">Getting started with Telephony devices from the HID Usage Tables</figcaption></figure>



<p>This course does not take into account other functionality, e.g.</p>



<ul class="wp-block-list">
<li>I can also hang up &#8211; Hook Switch, Usage ID <code>0x20</code>;</li>



<li>I have status LEDs &#8211; that&#8217;s a whole fun of redefining functions on the LED Page <code>0x08</code>;</li>
</ul>



<p>and so on. But for the time being this should be enough.</p>



<figure class="wp-block-image size-large"><img decoding="async" src="https://gergely.imreh.net/blog/wp-content/uploads/2023/08/Screenshot-2023-08-19-at-06.59.56-1024x924.png" alt="The Call Control usages abd their description from the HID Usage Tables document" class="wp-image-2806"/><figcaption class="wp-element-caption">Call Control functionality for Telefony devices</figcaption></figure>



<h3 class="wp-block-heading">Device implementation</h3>



<p>Fortunately we can stand on the shoulders of giants, that is the <a href="https://github.com/NicoHood/HID">Arduino HID Project</a> which implemented a bunch of different devices. And even though a &#8220;phone&#8221; like this is not among them, we can make some reasonable guesses how it would work.</p>



<p>Having said that, from a forum post that was also trying to do something similar (but based on the TinyUSB library):</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>HID report descriptor is very difficult thing to come up by oneself. You should google around, or dump report descriptor from existing device to copy/follow it.</p>
<cite><a href="https://github.com/hathach/tinyusb/discussions/667#discussioncomment-392454">hathach @ TinyUSB discussion 667</a></cite></blockquote>



<p>Okay, then do not come up with this stuff, instead let&#8217;s look for tools. The USB HID homepage links to the <a href="https://github.com/microsoft/hidtools">Microsoft HID Tools</a> to generate HID reports from a TOML-like language. Except it needs C# and I just wasn&#8217;t ready to dive in a side-quest to install &amp; learn a new toolchain.</p>



<p>So being lazy this way, a bit more sleuthing turned up <a href="https://web.archive.org/web/20210614160735/https://blog.noser.com/first-steps-with-an-usb-hid-report/">someone&#8217;s example HID report</a> for a device very close to what I&#8217;m trying to do, hurray!</p>



<p>I took this and started to poke around the HID project to see how other devices are implemented. Troubleshooting by using the ReSpeaker&#8217;s touch to adjust screen brightness up / down (as a &#8220;Consumer Device&#8221;) was also pretty neat! In the end I took the system buttons example and run with that one.</p>



<p>Having said that, the HID report is really just the interface. The devil is in how to implement actually creating the data packages that passes data according to the report definition. And this is the case when I wish I knew more C++ but copy-paste and some guesswork will have to do.</p>



<figure class="wp-block-image size-large"><img decoding="async" src="https://gergely.imreh.net/blog/wp-content/uploads/2023/08/Screenshot-2023-08-19-at-08.48.30-1024x519.png" alt="Screenshot of the Phone HID report definition code" class="wp-image-2814"/><figcaption class="wp-element-caption">Our minimal viable mute button&#8217;s HID report (<a href="https://github.com/imrehg/HID/blob/1851b68b008111734287f6ce4f894173ad21bb3f/src/MultiReport/Phone.cpp#L26C1-L41C1">source</a>)</figcaption></figure>



<p>The current result lives in the &#8220;<a href="https://github.com/imrehg/HID/tree/phone">phone&#8221; branch of my HID Project fork</a>, check for the &#8220;Phone&#8221; bits in &#8220;src/HID-APIs&#8221; and &#8220;MultiReport&#8221; folders, if interested.</p>



<h2 class="wp-block-heading">Minimal viable mute</h2>



<p>The implementation from this point on was pretty straightforward &#8211; since we cut back the scope so much&#8230;</p>



<p>The code to run on the ReSpeaker then just has to do the following:</p>



<ul class="wp-block-list">
<li>when touching one side, send a report with &#8220;Phone Mute&#8221; on</li>



<li>when touching the other, send a report with &#8220;Phone Mute&#8221; off</li>
</ul>



<p>And this is sort of simple<sup data-fn="c40b4257-a075-44fc-aefb-e036c5cb3543" class="fn"><a href="#c40b4257-a075-44fc-aefb-e036c5cb3543" id="c40b4257-a075-44fc-aefb-e036c5cb3543-link">3</a></sup> :</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="870" src="https://gergely.imreh.net/blog/wp-content/uploads/2023/08/arduino-code-for-phone-mute-events-1024x870.png" alt="Screenshot of the Arduino code to send the right mute events" class="wp-image-2821" srcset="https://gergely.imreh.net/blog/wp-content/uploads/2023/08/arduino-code-for-phone-mute-events-1024x870.png 1024w, https://gergely.imreh.net/blog/wp-content/uploads/2023/08/arduino-code-for-phone-mute-events-500x425.png 500w, https://gergely.imreh.net/blog/wp-content/uploads/2023/08/arduino-code-for-phone-mute-events-768x653.png 768w, https://gergely.imreh.net/blog/wp-content/uploads/2023/08/arduino-code-for-phone-mute-events.png 1198w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption class="wp-element-caption">Sending data on touch events in the simplest way</figcaption></figure>



<p id="demo">For the full use case there would be a lot more complexity for both reading and writing data from the host, controlling multiple peripherals (LEDs and buttons) and the whole logic around it. But for now, it&#8217;s good enough for a demo:</p>



<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-4-3 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe loading="lazy" title="A custom USB HID mute button for Google Meet" width="580" height="435" src="https://www.youtube.com/embed/Mz-B7sYGLUI?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
</div><figcaption class="wp-element-caption">A very quick demo</figcaption></figure>



<p>The code repository is available on Github at <a href="https://github.com/imrehg/arduino-usb-phone-hid">imrehg/arduino-usb-phone-hid</a>.</p>



<h2 class="wp-block-heading">Notes and Future work</h2>



<h3 class="wp-block-heading">The specs</h3>



<p>It&#8217;s great that stuff from 20+ years ago still works mostly the same way. The <a href="https://www.usb.org/sites/default/files/hut1_4.pdf">latest 1.4 version</a> of the HID Tables is nicely formatted, has a lot more device typed defined, but has much less support text. Originally I&#8217;ve read the <a href="https://www.usb.org/sites/default/files/documents/hut1_12v2.pdf">1.12v2 version</a> as that showed up in my search. Back then in 2004 they had an &#8220;examples&#8221; section (see the Telephone at Appendix 10!) which is useful to grok more of the fundamentals. </p>



<p>The newer version also has some devices types that looked suitable, but weren&#8217;t really: Generic Desktop Page (<code>0x01</code>) and <code>0xE0-E2</code> Usage IDs for Call Active LED, Call Mute Toggle, and Call Mute LED respectively. These didn&#8217;t seem to work with Meet, so it might be interesting to try implementing a device that does both and try other online call software.</p>



<p>I should also have read the spec more before diving into hacking on the HID implementation fork, as there&#8217;s a lot more information in the <a href="https://www.usb.org/document-library/device-class-definition-hid-111">HID Device Class Definition</a>, including how to construct the values for many of the fields (I&#8217;m looking at you &#8220;<code>INPUT (Cnst,Var,Abs)</code>&#8220;). RTFM is and remains a solid advice &#8211; and not just when one thinks there&#8217;s time.</p>



<p>Also regarding the specs: some of them I only find in the Internet Archive&#8217;s <a href="https://web.archive.org/">Wayback Machine</a>. If you encounter a good source that should be kept, always add it to the Wayback Machine and preserve it for your future selves and others!</p>



<p>This exploration of USB HID pulled on so many threads, and left so much unfinished, that it&#8217;s a fertile ground for the future, even more than most previous projects.</p>



<h3 class="wp-block-heading">More call functionality</h3>



<p>The most obvious thing is to implement the whole setup with the buttons. I&#8217;ve tried Hook Switch to hang up a call, that works too. Could add status lights, maybe throw in some &#8220;Active Call&#8221; LEDs, or so on. This requires better understanding how data is sent over the wire for USB and how to handle incoming data. The Arduino examples rarely seem to use the &#8220;Output&#8221; fields (ie. incoming data, output from the host&#8217;s point of view, but maybe <a href="https://github.com/hathach/tinyusb">TinyUSB</a> does ?</p>



<p>For this, it would be nice to find a different hardware platform that would make this more seamless (so I can concentrate on the software side more). If that platform would lend itself to be reproduced or made stand alone, that would be even nicer: imaging brining my little call control box that can be used with other computers easily as well&#8230;</p>



<h3 class="wp-block-heading">Implement more USB HID devices</h3>



<p>The <a href="https://github.com/NicoHood/HID">Arduino HID project</a> has a bunch of devices implemented, but there are an infinite numbers that could be added. Unfortunately for Arduino it is harder to add more device types as an add-on to this library versus the current &#8220;forked&#8221; approach<sup data-fn="d18cdbdc-1733-40b6-a512-81c55a158ce0" class="fn"><a href="#d18cdbdc-1733-40b6-a512-81c55a158ce0" id="d18cdbdc-1733-40b6-a512-81c55a158ce0-link">4</a></sup>, so new decices should be in the main project, eventually.</p>



<p>So far there&#8217;s no Telephony device implemented there and it would be nice to find the right level of abstraction that works. The library doesn&#8217;t implement specific HID table pages, but specific usages or a subset of a usage. Thus like always, the hardest part would likely be setting the right interface (the right specs and &#8220;API&#8221;) for a new device to implement both the HID reports and the functions that manipulate what&#8217;s being sent and when.</p>



<p>On the other hand, that does sound like a fun experiment, and I&#8217;d look forward to adding 3D Game Controllers (Game Controls Page <code>0x05</code>), Environmental Sensors (Sensors Page <code>0x20</code>, Usage ID <code>0x30-3B</code>), &#8230; or even a Submarine Simulation Device (Simulation Device page <code>0x02</code>, usage id <code>0x05</code>). These are stuff I go to Hackerspaces for&#8230;</p>



<h3 class="wp-block-heading">WebHID for internet plus USB</h3>



<p>While debugging this HID device behaviour, I found also <a href="https://developer.mozilla.org/en-US/docs/Web/API/WebHID_API">WebHID</a> that brings such devices to the web. This feature seems to be behind Meet&#8217;s and other phone systems like <a href="https://www.3cx.com/blog/docs/webhid-headset-integration/">3CX</a> expanding USB support outside of the OS and into the browser. And no, <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=1835412">Firefox does not support it</a>, furthermore <a href="https://mozilla.github.io/standards-positions/#webhid">declined supporting it</a>.</p>



<p>Nonetheless it&#8217;s very cool that (if I upskill a bit), I can create a web page that would help me debug such HID development:</p>



<ul class="wp-block-list">
<li><a href="https://developer.mozilla.org/en-US/docs/Web/API/HID/requestDevice">request devices</a> that are filtered in various ways (vendor, product is standard, but usage page and explicit usage is the main key). This is likely what Meet does as well, &#8220;just gimme devices with Telephony usage page (or Phone usage? Need to check exactly) </li>



<li><a href="https://developer.mozilla.org/en-US/docs/Web/API/HIDDevice/collections">read the HID report collections</a> sent by the device, so the results can be debugged, and</li>



<li><a href="https://developer.mozilla.org/en-US/docs/Web/API/HIDInputReportEvent">read device input events</a> that we can then either log for debugging or in an application react to to it</li>
</ul>



<p>This opens a lot more mashup opportunities by the dozen.</p>



<h2 class="wp-block-heading">Finally</h2>



<p>Unlike most other projects I had where I&#8217;m focused on one specific outcome, this turned out to be more focusing on getting a new toolkit (custom USB devices) up and running, so I can think about a wider <em>types</em> of projects to do. In that sense, this feels a big success, even if I know how little I know about programming outside of my day-to-day environment. But ignorance is not a bliss.</p>



<p>And now, going on mute.</p>


<ol class="wp-block-footnotes"><li id="7509dd7d-2867-4955-808e-d9bd3a9e8cd4">Many moons past I used to use a Jabra Evolve 80, that has <a href="https://www.manualslib.com/manual/1021017/Jabra-Evolve-80.html?page=16#manual">a USB accessory</a> controlling call features, so I did have first hand example of what sort of experience I&#8217;d like. <a href="#7509dd7d-2867-4955-808e-d9bd3a9e8cd4-link" aria-label="Jump to footnote reference 1"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/21a9.png" alt="↩" class="wp-smiley" style="height: 1em; max-height: 1em;" />︎</a></li><li id="17ce950a-5b32-45de-8a5c-2464146a1840">I&#8217;ve tried reviewing the <a href="https://github.com/respeaker/get_started_with_respeaker/blob/master/files/RespeakerCorev1.0_Schematic.pdf">hardware schematics</a>, looking into the <a href="https://github.com/respeaker/respeaker_arduino_library/blob/4e04f8c72fa53beeb27dacd8d729a90f79202db7/pixels.cpp">pixel ring control functions</a>, and given that the LEDs seems standard I&#8217;ve also attempted to use the <a href="http://fastled.io/">FastLED library</a> to drive them instead, so far nothing. I still bet on hardware differences from final schematic + my inability to debug it, but it can be faulty hardware just as well. Needs more effort &#8211; in the future. <a href="#17ce950a-5b32-45de-8a5c-2464146a1840-link" aria-label="Jump to footnote reference 2"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/21a9.png" alt="↩" class="wp-smiley" style="height: 1em; max-height: 1em;" />︎</a></li><li id="c40b4257-a075-44fc-aefb-e036c5cb3543">The Arduino code became more &#8220;simple&#8221; once I realised that things set up this way do not need debouncing for the touch sensors. In other cases that would be essential, there&#8217;s sooo much flaky signal to use those terminals as momentary switches or similar. <a href="#c40b4257-a075-44fc-aefb-e036c5cb3543-link" aria-label="Jump to footnote reference 3"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/21a9.png" alt="↩" class="wp-smiley" style="height: 1em; max-height: 1em;" />︎</a></li><li id="d18cdbdc-1733-40b6-a512-81c55a158ce0">At least I don&#8217;t know how nicely extend a library for C++, if that&#8217;s even possible. Keen to learn, though. <a href="#d18cdbdc-1733-40b6-a512-81c55a158ce0-link" aria-label="Jump to footnote reference 4"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/21a9.png" alt="↩" class="wp-smiley" style="height: 1em; max-height: 1em;" />︎</a></li></ol><p>The post <a href="https://gergely.imreh.net/blog/2023/08/making-a-usb-mute-button-for-online-meetings/">Making a USB Mute Button for Online Meetings</a> appeared first on <a href="https://gergely.imreh.net/blog">ClickedyClick</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://gergely.imreh.net/blog/2023/08/making-a-usb-mute-button-for-online-meetings/feed/</wfw:commentRss>
			<slash:comments>2</slash:comments>
		
		
			</item>
		<item>
		<title>Doing the Easy Problems on Leetcode</title>
		<link>https://gergely.imreh.net/blog/2023/08/doing-the-easy-problems-on-leetcode/</link>
					<comments>https://gergely.imreh.net/blog/2023/08/doing-the-easy-problems-on-leetcode/#comments</comments>
		
		<dc:creator><![CDATA[Gergely Imreh]]></dc:creator>
		<pubDate>Sun, 13 Aug 2023 10:21:23 +0000</pubDate>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[leetcode]]></category>
		<guid isPermaLink="false">https://gergely.imreh.net/blog/?p=2793</guid>

					<description><![CDATA[<p>Making the most of this narrow nieche by learning new programming patterns and techniques that likely pop up in day-to-day work, and easing into learning extra programming languages.</p>
<p>The post <a href="https://gergely.imreh.net/blog/2023/08/doing-the-easy-problems-on-leetcode/">Doing the Easy Problems on Leetcode</a> appeared first on <a href="https://gergely.imreh.net/blog">ClickedyClick</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Over the last decade I seem to have been working in environments, where many engineers and engineering minded people spend time with programming puzzles and coding challenges. Let it be <a href="https://adventofcode.com/">Advent of Code</a>, <a href="https://projecteuler.net/">Project Euler</a>, <a href="https://exercism.org/">Exercism</a>, <a href="https://www.topcoder.com/community/arena">TopCoder</a>, or <a href="https://leetcode.com/">Leetcode</a>. I&#8217;ve tried all of these before (and probably a few more that I no longer remember), though with various amount of time spent all fired up, and then fizzled out. Recently I&#8217;ve <a href="https://leetcode.com/imrehg/">picked up</a> Leetcode, since from the above list that&#8217;s why I&#8217;ve spent the <em>least</em> amount of time with and others mentioned using it a way to relax and learn on weekends (suspend judgement on the wisdom of that for now).</p>



<p>Thus in the last two weeks I was solving problems, though not just any problems, but went in mostly for the <em>Easy</em> ones. These few dozen problems and short amount of time doesn&#8217;t give me a deep impression, but from past experiences I can still distill some lessons that help shaping future experiments.</p>



<p>The purpose of using the Easy problems is different from e.g. going all in for puzzle-solving fun, which is likely in the Hard ones. Rather than that, I think easy problems can be used for learning some new techniques, looking for common patterns, and becoming more polygot.</p>



<span id="more-2793"></span>



<h3 class="wp-block-heading">New Techniques &amp; Common Patterns</h3>



<p>It&#8217;s 100% that I&#8217;ll be able to solve the Easy problems by myself (otherwise I should give back my nerd card). On the other hand, there are always more than one way of doing things.</p>



<p>For example, many <a href="https://pandas.pydata.org/">Pandas</a> problems on Leetcode could be done with various &#8220;merge&#8221; or &#8220;join&#8221; application, or oneliners versus intermediate variables. It&#8217;s fine to know one, but then checking the solutions by others, and finding the alternate ways, trying them out, and seeing their tradeoffs.</p>



<p>Another kind I&#8217;ve encoungtered, that&#8217;s maybe only new to me, but illustrates things, is solving certain problems while iterating one way (incrementing counters, from left to right, etc&#8230;), while in reverse (decrementing, right to left, etc&#8230;) the solution might become neater or more obvious.</p>



<p>After solving the problem one way, just going through others examples, looking for options that I haven&#8217;t considered, and pitching them against what I did originally definitely expands my toolkit. In addition since these are easy problems, it affects more common situations, code that I would encounter day to day.</p>



<p>Skipping through the other shared solutions I can also get to see common patterns. It&#8217;s a bit like <a href="https://en.wikipedia.org/wiki/Statistical_mechanics">statistical mechanics</a> that while among the solutions there&#8217;s loads of crap<sup data-fn="956f709a-a462-4807-b754-a70f155aa486" class="fn"><a href="#956f709a-a462-4807-b754-a70f155aa486" id="956f709a-a462-4807-b754-a70f155aa486-link">1</a></sup> but <em>on average</em> the patterns of solutions appears that is relevant for a given language. </p>



<h3 class="wp-block-heading">Polygot Programming</h3>



<p>Given that most Leetcode problems are allowed to be solved in multiple languages, that supports learning across languages very well. For example Pandas problems paired with solutions in MySQL: sometimes the pattern of solutions were very similar in the two, other times needed very different thiking to get to a solution that felt &#8220;right&#8221;-ish. Similar case in the other combination of Python and Rust that I&#8217;m trying to dive into.</p>



<p>The trick is to try to solve things in any way at first, and then do the previous &#8220;look for techniques and patterns&#8221; to build up the experience.</p>



<p>Using Easy problems in this case gives a lot of different, simple use cases where the basics can be compared easier, focusing on the language similarities and differences. The problem difficulty then doesn&#8217;t muddy the waters.</p>



<h3 class="wp-block-heading">Build Up Programming Muscles</h3>



<p>The Easy problems have smaller scope (that&#8217;s why they are easy), and seems to allow improving pattern recognition, on which other, more difficult problems can build on. It&#8217;s all about building shortcuts based on encountering similar stuff and making the connection, and building <a href="https://en.wikipedia.org/wiki/Chunking_(psychology)">chunks</a> that can be reused later.</p>



<p>Most of the day-to-day programming likely encounters these sorts of easy problems anyways, thus my hypothesies that they can be good bang-for-buck for improving baseline effectiveness. Of course if someone always works on big-hairy-problems, this would stand. But how common is that?</p>



<h3 class="wp-block-heading">Flipside: Why Not Do This?</h3>



<p>The incentives at Leetcode doesn&#8217;t seem to align towards <em>quality</em> overall. When developing for efficiency, the run result timing seems to support that but the variance is way too high to be really useful. The solution sharing and feedback also seems to support that, but there&#8217;s way too much noise and broken feedback looks to be effective at that. Thus the quality of the above mentioned steps really depends on how much effort I put in there. It&#8217;s very easy to grind (get a lot of problems done)<sup data-fn="bcc1e3d0-d160-4c2e-8561-fc7760e5f397" class="fn"><a href="#bcc1e3d0-d160-4c2e-8561-fc7760e5f397" id="bcc1e3d0-d160-4c2e-8561-fc7760e5f397-link">2</a></sup>, but learn almost nothing, or learn the wrong patterns.</p>



<p>Wrong patterns is indeed the main culprit. The problems are not set up to be &#8220;production quality&#8221; that would make one a good engineer. Rather than doing things in a clever way, or going in for the oneliners at the expense of any readability, or using a solution that is more hard-coded &amp; tailored to a narrow case rather than with a bit nicer way that generalises, etc&#8230;</p>



<p>Most of the time I also cannot even really remember the solution from even an hour ago, probably the side effect of going for quantity (easy) instead of quality (hard problems). </p>



<h3 class="wp-block-heading">Next Steps</h3>



<p>Leetcode is definitely looks like a reasonable tool to have in one&#8217;s kit, though not as the main one. I think I&#8217;ll do look around more among the Easy problems to see more patterns, but for more interesting ones I&#8217;d go gradually up, otherwise I&#8217;d just drop it soon enough.</p>



<p>On the other hand, the more useful step might be picking up my learning paths on Exercism, where a few things are diametrically opposite: more quality focused, direct feedback from knowledgeable people, and empracing iterative improvement. It seems less polygot (there are many languages, but they are learning paths independent from each other, even if some problems do repeat between them), but that&#8217;s not a showstopper.</p>



<p>The main thing is, though to continue a habit that is created by this experiment: deliberately practicing programming, seeking out alternatives, and not taking them at face value.</p>


<ol class="wp-block-footnotes"><li id="956f709a-a462-4807-b754-a70f155aa486">Given the gamified upvoting system, it&#8217;s no surprise that it creates so much spam. <a href="#956f709a-a462-4807-b754-a70f155aa486-link" aria-label="Jump to footnote reference 1"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/21a9.png" alt="↩" class="wp-smiley" style="height: 1em; max-height: 1em;" />︎</a></li><li id="bcc1e3d0-d160-4c2e-8561-fc7760e5f397">I&#8217;m still surprised that with 36 Easy problems, I&#8217;ve already soved more of them than almost 70% of people. <a href="#bcc1e3d0-d160-4c2e-8561-fc7760e5f397-link" aria-label="Jump to footnote reference 2"><img src="https://s.w.org/images/core/emoji/17.0.2/72x72/21a9.png" alt="↩" class="wp-smiley" style="height: 1em; max-height: 1em;" />︎</a></li></ol><p>The post <a href="https://gergely.imreh.net/blog/2023/08/doing-the-easy-problems-on-leetcode/">Doing the Easy Problems on Leetcode</a> appeared first on <a href="https://gergely.imreh.net/blog">ClickedyClick</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://gergely.imreh.net/blog/2023/08/doing-the-easy-problems-on-leetcode/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Programming challenge: Protohackers 3</title>
		<link>https://gergely.imreh.net/blog/2022/09/programming-challenge-protohackers-3/</link>
					<comments>https://gergely.imreh.net/blog/2022/09/programming-challenge-protohackers-3/#respond</comments>
		
		<dc:creator><![CDATA[Gergely Imreh]]></dc:creator>
		<pubDate>Sat, 24 Sep 2022 09:33:28 +0000</pubDate>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[protohackers]]></category>
		<category><![CDATA[python]]></category>
		<guid isPermaLink="false">https://gergely.imreh.net/blog/?p=2720</guid>

					<description><![CDATA[<p>Incursion into server programming with Python and failing in a productive way.</p>
<p>The post <a href="https://gergely.imreh.net/blog/2022/09/programming-challenge-protohackers-3/">Programming challenge: Protohackers 3</a> appeared first on <a href="https://gergely.imreh.net/blog">ClickedyClick</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p><a href="https://protohackers.com/">Protohackers</a> is a server programming challenge, where various network protocols are set as a problem. It has started not so long ago, and <a href="https://protohackers.com/problem/3">the No 3. challenge</a> was just released yesterday, aiming at creating a simple (&#8220;Budget&#8221;) multi-user chat server. I thought I <s>sacrifice a decent part of my weekend</s> give it a honest try. This is the short story of trying, failing, then getting more knowledge out than I&#8217;ve expected.</p>



<p>Definitely wanted to tackle it using Python as that&#8217;s my current utility language that I want to know most about. Since the aim of Protohackers, I think, is to go from scratch, I set to use only the standard library. With some poking around documentation I ended up choosing <a href="https://docs.python.org/3/library/socketserver.html#module-socketserver">SocketServer</a> as the basis of the work. It seemed suitable, but there was a severe dearth of non-dummy code and deeper explanation. In a couple of hours I did make some progress, though, that already felt exciting:</p>



<ul class="wp-block-list"><li>Figured out (to some extent) the purpose of the server / handler parts in practice</li><li>Made things multi-user with data shared across connections</li><li>Grokked a bit the lifecycle of the requests, but definitely not fully, especially not how disconnections happen.</li></ul>



<p>Still it was working to some extent, I <em>could</em> make a server that functioned for a certain definition of &#8220;functioned&#8221;, as the logs attest:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="232" src="https://gergely.imreh.net/blog/wp-content/uploads/2022/09/budget-chat-server-logs-1024x232.png" alt="Console log of server messages while trying my Budget Chat Server implementation." class="wp-image-2724" srcset="https://gergely.imreh.net/blog/wp-content/uploads/2022/09/budget-chat-server-logs-1024x232.png 1024w, https://gergely.imreh.net/blog/wp-content/uploads/2022/09/budget-chat-server-logs-500x113.png 500w, https://gergely.imreh.net/blog/wp-content/uploads/2022/09/budget-chat-server-logs-768x174.png 768w, https://gergely.imreh.net/blog/wp-content/uploads/2022/09/budget-chat-server-logs-1200x272.png 1200w, https://gergely.imreh.net/blog/wp-content/uploads/2022/09/budget-chat-server-logs.png 1386w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption>Server logs from trying my Budget Chat Server</figcaption></figure>



<span id="more-2720"></span>



<p>On the other hand, ended up in a relative dead-end, as some message ordering issues kicked in, and reliably failed the test here, not knowing much what to try next just yet:</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="836" src="https://gergely.imreh.net/blog/wp-content/uploads/2022/09/protohackers-3-failure-1024x836.png" alt="" class="wp-image-2721" srcset="https://gergely.imreh.net/blog/wp-content/uploads/2022/09/protohackers-3-failure-1024x836.png 1024w, https://gergely.imreh.net/blog/wp-content/uploads/2022/09/protohackers-3-failure-500x408.png 500w, https://gergely.imreh.net/blog/wp-content/uploads/2022/09/protohackers-3-failure-768x627.png 768w, https://gergely.imreh.net/blog/wp-content/uploads/2022/09/protohackers-3-failure-1536x1254.png 1536w, https://gergely.imreh.net/blog/wp-content/uploads/2022/09/protohackers-3-failure-1200x980.png 1200w, https://gergely.imreh.net/blog/wp-content/uploads/2022/09/protohackers-3-failure.png 1568w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption>Testing my in-progress solution, and failing.</figcaption></figure>



<p>Since it&#8217;s a learning exercise and definitely not a competition on my part, I started to procrastinate. Not long before I&#8217;ve looked at the status of the <a href="https://protohackers.com/leaderboard">leaderboard</a>. Funnily enough, looking at the top entries, they were linking to the repositories where their solutions were! <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<h2 class="wp-block-heading">Shoulders of Giants</h2>



<p>Here&#8217;s my surprise and delight started, though. Within the first 7 entries there were 3 with Python implementations that included code! Even better, they actually covered 3 completely different ways of solving the task. Jackpot, really!</p>



<ol class="wp-block-list"><li>The <a href="https://github.com/pyxyne/protohackers/blob/9c4b26ecf0b274755856d5e1e3104bfa774a12f9/p3_chat.py">first solution</a> used pure <a href="https://docs.python.org/3/library/socket.html">sockets</a>, which is quite versatile if I&#8217;d want to go all-in on low-level networking in the future. It had quite a lot of helper code, though which makes it look like a pretty decent effort to duplicate.</li><li>The <a href="https://github.com/simon816/Protohackers-solutions/blob/f10c0f606a3688e7486d70a4914cd22e4d781e07/3/server.py">second solution</a> went with <a href="https://docs.python.org/3/library/socketserver.html">SocketServer</a> just like I&#8217;ve tried, and that is nice to dig in a bit more, given how small the whole code is. The main thing here was that I should have understood from the problem description this being a <a href="https://docs.python.org/3/library/socketserver.html#socketserver.StreamRequestHandler">Streaming</a> TCP connection case. Looks like streaming is the part that takes care of a lot of details, including the connection/disconnection that plagued me. Bam!</li><li>The <a href="https://github.com/LiraNuna/protohackers/blob/566b90aa7e17929f7d87a4fa9468cdb332bdf4ce/3%20-%20budget-chat/budget-chat.py">third solution</a> then used <a href="https://docs.python.org/3/library/asyncio.html?highlight=asyncio">asyncio</a>, to take it in a different direction again. It&#8217;s amazing how simple it all is when the relevant components and abstractions are understood.</li></ol>



<p>Which one is the most tempting solution to follow (and/or learn from)? Pure sockets are likely just a fallback option when there&#8217;s nothing else. On the SocketServer vs asyncio front however there was some useful <a href="https://stackoverflow.com/a/40177631">StackOverflow</a> discussion, even if a bit dated, coming from 2016. It pointed at the different use of threading and event loops. I guess this would make this answer a bit unsatisfying, but quite realistic: <em>learn both and know when either is applicable for your use case</em>. </p>



<h2 class="wp-block-heading">What did we learn?</h2>



<p>In the end I haven&#8217;t finished my code yet. Reading the existing solutions influences me and just adapting what others did and submit would feel like cheating (to myself). The way to resolve this is setting your own goals on top of the original challenge. Here I picked the following, and achieving these would complete things for me:</p>



<ul class="wp-block-list"><li>Use proper project structure and try out <a href="https://pdm.fming.dev/latest/">PDM</a></li><li>Figure out how to set up the project &amp; code to be testable with <a href="https://docs.pytest.org/en/7.1.x/">pytest</a> (basically grok testing of programs that run servers)</li></ul>



<p>The combination of these focuses on something akin to &#8220;going to production&#8221;, besides obviously writing the actual code, which is very much relevant to my interests.</p>



<p>So far I haven&#8217;t seen many examples of testing SocketServer, though <a href="https://github.com/python/cpython/blob/c5b750dc0b4d4e58047c9d93c635fa26b06562f7/Lib/test/test_socketserver.py">there&#8217;s Python&#8217;s own test suit</a> that could be a starting place. It has a lot of super useful helper functions (such as finding an unused port to run the server on), but overall seems a lot of boilerplate too. For asyncio I haven&#8217;t looked around yet. It being &#8220;cooler&#8221; there might be more discussion around it, but it&#8217;s by no means a given. Would be interesting to combine this with a Basic Chat client as well.</p>



<p>Another impression from today&#8217;s effort is that Python modules are documented to very varying levels. Their complexity definitely jumps when I try to go from dummy stuff to anything useful. For example here understanding the proper role and interaction of the Server and Handler parts of this multi-user environment.</p>



<p>I&#8217;m also acutely aware that my networking knowledge is very patchy regardless of doing networking-adjacent stuff for decades. It&#8217;s a very useful frontier to tackle when I have a chance.</p>



<p>Finally, <a href="https://ngrok.com/">ngrok</a> is still very cool tool, nice to be able to sit in a cafe and safely exposing a server to the internet.</p>
<p>The post <a href="https://gergely.imreh.net/blog/2022/09/programming-challenge-protohackers-3/">Programming challenge: Protohackers 3</a> appeared first on <a href="https://gergely.imreh.net/blog">ClickedyClick</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://gergely.imreh.net/blog/2022/09/programming-challenge-protohackers-3/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>A personal finance data pipeline project</title>
		<link>https://gergely.imreh.net/blog/2022/08/a-personal-finance-data-pipeline-project/</link>
					<comments>https://gergely.imreh.net/blog/2022/08/a-personal-finance-data-pipeline-project/#respond</comments>
		
		<dc:creator><![CDATA[Gergely Imreh]]></dc:creator>
		<pubDate>Thu, 04 Aug 2022 03:45:58 +0000</pubDate>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Taiwan]]></category>
		<category><![CDATA[automation]]></category>
		<category><![CDATA[bigquery]]></category>
		<category><![CDATA[gcp]]></category>
		<guid isPermaLink="false">https://gergely.imreh.net/blog/?p=2691</guid>

					<description><![CDATA[<p>If your bank updates you through password-protected PDFs in emails and you are a programmer, you make some finance data extract lemonade.</p>
<p>The post <a href="https://gergely.imreh.net/blog/2022/08/a-personal-finance-data-pipeline-project/">A personal finance data pipeline project</a> appeared first on <a href="https://gergely.imreh.net/blog">ClickedyClick</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>I had received a (family) project brief recently. In Taiwan many credit/debit cards have various promotions and deal, and many of them depend on one&#8217;s monthly spending, for example &#8220;below X <a href="https://en.wikipedia.org/wiki/New_Taiwan_dollar">NTD</a> spending each month, get Y% cashback&#8221;. People also have a lot of different cards, so playing these off each other can be nice pocket change, but have to keep an eye on whether where one is compared to the max limit (X). So the project comes from here: easy/easier tracking of where one specific card&#8217;s spending is within the monthly period. That doesn&#8217;t sound too difficult, right? Except the options for these are: </p>



<ol class="wp-block-list"><li>A banking website with CAPTCHAs and no programmatic access</li><li>An email received each day with an password-protected PDF containing the last day&#8217;s transactions in a table</li></ol>



<p>Neither of these are fully appetizing to tackle, but both are similar to bits that I do at #dayjob, but 2. was a bit closer to what I&#8217;ve been doing recently, so that&#8217;s where I landed. That is:</p>



<ul class="wp-block-list"><li>Forward the received email (the email provider does it)</li><li>Receive it in some compute environment</li><li>Decrypt the PDF</li><li>Extract the transaction data table</li><li>Clean and process the tabular data</li><li>Put raw in some data warehouse</li><li>Transform data to get the right aggregation</li><li>&#8230;</li><li>Literally profit?</li></ul>



<p>I was surprised how quick this actually worked out in the end (if &#8220;half a weekend&#8221; is quick), and indeed this can be a first piece of a &#8220;personal finance data warehouse&#8221;.</p>



<span id="more-2691"></span>



<h2 class="wp-block-heading">Technical implementation</h2>



<p>I wanted to have the final setup run in &#8220;The Cloud&#8221;, as that&#8217;s one less thing to worry about. The most obvious arrangement, based on past experiences was combing <a href="https://docs.aws.amazon.com/ses/latest/dg/Welcome.html">AWS Simple Email Service</a> (SES) to receive an email, and a <a href="https://aws.amazon.com/lambda/">Lambda</a> to run serverless processing. On the data warehouse side the real obvious choice is <a href="https://cloud.google.com/bigquery/">GCP&#8217;s BigQuery</a>, however, so I looked into what would be a similar arrangement for the processing pieces if I want to put everything into a single cloud provider.</p>



<p>After some docs diving the most natural arrangement on GCP seemed to be quite different: an <a href="https://cloud.google.com/appengine/">App Engine</a> deployment with <a href="https://cloud.google.com/appengine/docs/standard/python3/services/mail">Mail API </a>enabled. This gives a receiving domain name (@[Cloud-Project-ID].appspotmail.com) , and every email sent there is just passed to the server that is running in App Engine. This seemed pretty simple! App Engine also has a free tier, though that comes with pretty small memory limits, which features in this story too.</p>



<p>The final result of the server part is <a href="https://github.com/imrehg/finance-extract/">shared on GitHub</a>, and should be easy to reuse or extend.</p>



<h3 class="wp-block-heading">PDF processing</h3>



<p>Getting the attachments out of the email was pretty straightforward with the Mail API, so the first heavier task was opening the encrypted PDF and getting the table out of it. Opening PDFs are quite common, but the table extraction was a bit of a journey.</p>



<h4 class="wp-block-heading">False try</h4>



<p>First I was searching around (as anyone else does) for someone else&#8217;s rundown of the options, <a href="https://www.geeksforgeeks.org/how-to-extract-pdf-tables-in-python/">as an example</a>. From there I honed in on <a href="https://pikepdf.readthedocs.io/en/latest/">pikepdf</a> to open the password-protected files, an <a href="https://tabula-py.readthedocs.io/en/latest/">tabula-py</a> which seemed handy to extract tables right into <a href="https://pandas.pydata.org/">Pandas</a> DataFrames. One subtlety was that tabula-py is just a wrapper around <a href="https://github.com/tabulapdf/tabula-java">tabula-java</a> to do the extraction, and needs a Java environment installed. The free tier of App Engine uses their <a href="https://cloud.google.com/appengine/docs/standard/">standard</a> environment where all I have is my code and &#8220;requirements.txt&#8221; to install my python dependencies, so it&#8217;s obvious how would I get Java into the deployment correctly.</p>



<p>Enter the scene <a href="https://github.com/jyksnw/install-jdk">install-jdk</a> which can install the Java environment at runtime. That was sufficiently crazy hack to actually work, and <a href="https://github.com/imrehg/finance-extract/blob/19fa754b72b39aac246bf385e2ebeff7cf35b1ad/main.py#L14-L28">it did work</a>. Or so it seemed, since the data was processed and showing up in BigQuery, when I&#8217;ve sent test emails into the system.</p>



<p>Upon closer inspection, though, there were loads of duplicate lines. Between signing off in the evening, and checking it in the morning, I had bunches of them, and were still coming in&#8230;</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="609" height="307" src="https://gergely.imreh.net/blog/wp-content/uploads/2022/08/duplicated-data-extraction.png" alt="BigQuery view of duplicated data" class="wp-image-2705" srcset="https://gergely.imreh.net/blog/wp-content/uploads/2022/08/duplicated-data-extraction.png 609w, https://gergely.imreh.net/blog/wp-content/uploads/2022/08/duplicated-data-extraction-500x252.png 500w" sizes="auto, (max-width: 609px) 100vw, 609px" /><figcaption>Sometimes duplicated data sneaks in from software issues</figcaption></figure>



<p>I should have checked the logs earlier, because once dig in, there were bunches of &#8220;server errors&#8221; listed that didn&#8217;t connect to any programming errors that I might have made, rather than (here comes the epiphany) instances being killed for being out of memory / blowing their memory budget (of 256MB for the free tier). Thus what happened is:</p>



<ul class="wp-block-list"><li>the Java run of tabula was just using too much memory while processing the PDFs</li><li>it finished processing and like loaded the data but it takes a bit of time</li><li>GCP catches up and kills the instance while that is still going on, and reports to the Mail API that the email <em>hasn&#8217;t been</em> properly handled (server error during that process)</li><li>Whatever is handling the incoming email queue in GCP will just just keep the data and retries later</li><li>The cycle repeats&#8230;</li></ul>



<p>This didn&#8217;t seem very helpful and the repeat emails were piling up in whatever (opaque, to me) system GCP has, so needed a quick replace of tabulate with something lighter&#8230;</p>



<h4 class="wp-block-heading">Worse is better and actually good</h4>



<p>Going down the list of recommended libraries, next I looked at <a href="https://camelot-py.readthedocs.io/en/master/">camelot-py</a> which looks great, but needs <a href="https://opencv.org/">OpenCV</a> on the machine to do its work, so back to the &#8220;how to install OS packages on Standard AppEngine?&#8221; question. For some extra inspiration I was looking at <a href="https://github.com/camelot-dev/camelot/wiki/Comparison-with-other-PDF-Table-Extraction-libraries-and-tools">camelot&#8217;s comparison with other similar tools page</a> and it was a bit disappointing (though not surprising) that pretty much every other library is &#8220;worse&#8221; on various PDFs compared to camelot. Just for kicks I did try some out, and <a href="https://pypi.org/project/pdfplumber/">pdfplumber</a> actually delivered:</p>



<ul class="wp-block-list"><li>it does actually work on the example PDFs I had from previous bank emails</li><li>nothing else beside pip install</li><li>it can actually handle decrypting the PDF as well, so helper libraries can be dropped</li><li>the extracted data is in Python tables, but it&#8217;s just an extra line to get DataFrames, so no sweat</li><li>The extracted data was actually better quality than tabula&#8217;s, so had to do fewer cleanup steps!</li></ul>



<p>This was a pure win, and indeed it&#8217;s worth looking stuff that works with the data at hand, not ignoring the edge cases, but also not overly emphasizing being able to do &#8220;everything&#8221; when there&#8217;s a clear target of what &#8220;thing&#8221; needs to work. (Potential technical debt considered too).</p>



<h3 class="wp-block-heading">Data transformations and visibility</h3>



<p>Now the data sits in BigQuery properly:</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="667" height="330" src="https://gergely.imreh.net/blog/wp-content/uploads/2022/08/bigquery-finance-data.png" alt="BigQuery financial data table" class="wp-image-2708" srcset="https://gergely.imreh.net/blog/wp-content/uploads/2022/08/bigquery-finance-data.png 667w, https://gergely.imreh.net/blog/wp-content/uploads/2022/08/bigquery-finance-data-500x247.png 500w" sizes="auto, (max-width: 667px) 100vw, 667px" /><figcaption>Actual data in the works.</figcaption></figure>



<p>The raw transaction data loaded into BigQuery was the first step, but still need to answer the question: in this billing period, how much have I spent?</p>



<p>Not being a data analyst (or not yet?:), this took a bit of figuring out. As other novices share their bit of &#8220;clever code&#8221; when it&#8217;s actually trivial to the experts, I&#8217;m sharing here the bit of SQL queries in a similar &#8220;that was fun to figure out, wasn&#8217;t it?&#8221; way. I&#8217;m sure it can be much improved, but it&#8217;s a good reminder for myself as well.</p>



<p>Given that my billing period starts on the 23rd of the month, get the aggregated value of transactions for each billing period: </p>



<pre title="monthly-aggregation.sql" class="wp-block-code has-small-font-size"><code lang="sql" class="language-sql">WITH
  Aggregated AS (
  SELECT
    DATE(TransactionDate, 'Asia/Taipei') AS day,
    TransactionAmountNTD
  FROM
    `personal-data-warehouse.finance.huanan` ),
  calendar AS (
  SELECT
    day,
    -- Find the last day before the new interval
    DATE_SUB(
      DATE_ADD(
        day,
        INTERVAL 1 Month),
      INTERVAL 1 DAY
    ) AS endday
  FROM
    UNNEST (
      GENERATE_DATE_ARRAY(
        -- Start date in the past before any data,
        -- on the right day of the month for
        -- the billing cycle.
        '2022-05-23', 
        CURRENT_DATE('Asia/Taipei'),
        INTERVAL 1 Month
      )
    ) AS day
) SELECT
  SUM(TransactionAmountNTD) AS `MonthlyTransactions`,
  COUNT(*) AS `TransactionCount`,
  EXTRACT(Year FROM c.day) AS `Year`,
  EXTRACT(Month FROM c.day) AS `Month`,
  FORMAT('%d-%02d', EXTRACT(Year
    FROM
      c.day), EXTRACT(Month
    FROM
      c.day)
  ) AS `Interval`
FROM
  calendar AS c
JOIN
  Aggregated AS a
ON
  a.day BETWEEN c.day AND c.endday
GROUP BY
  c.day</code></pre>



<p>Good stuff on the date array and joining with a &#8220;between&#8221; statement, those are the main TIL. They also already came up at #dayjob, which was very satisfying.</p>



<p>From here the data I surface in a connected <a href="https://cloud.google.com/bigquery/docs/connected-sheets">Google Sheet</a> which is pretty practical, though leaves the &#8220;being notified when I approach/reach X&#8221; out, but that&#8217;s fine for now.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="874" height="445" src="https://gergely.imreh.net/blog/wp-content/uploads/2022/08/google-sheet-connected-to-bigquery.png" alt="" class="wp-image-2709" srcset="https://gergely.imreh.net/blog/wp-content/uploads/2022/08/google-sheet-connected-to-bigquery.png 874w, https://gergely.imreh.net/blog/wp-content/uploads/2022/08/google-sheet-connected-to-bigquery-500x255.png 500w, https://gergely.imreh.net/blog/wp-content/uploads/2022/08/google-sheet-connected-to-bigquery-768x391.png 768w" sizes="auto, (max-width: 874px) 100vw, 874px" /><figcaption>Connected tables view in Sheets</figcaption></figure>



<h3 class="wp-block-heading">Testing and getting to &#8220;production&#8221;</h3>



<p>One good thing about personal projects is that I can make them as &#8220;good&#8221; as I want to (or as &#8220;bad&#8221;, of course), which usually results in an unhealthy amount of tweaking, trying out various best practices to see if they work, and so on. Here I really wanted to get the system well tested, for example, which turned out to take <em>loads more time</em> than actually writing the original service. Actually, there&#8217;s nothing surprising about that for software engineering professionals, but still can catch people off-guard.</p>



<p>Here the tricky parts came from two areas: <a href="https://fastapi.tiangolo.com/">FastAPI</a> settings and cloud service integrations.</p>



<p>The former is always a bit of an issue, depending on how the code uses the settings (whether things can be patched well at testing time), but here I also used a trick for the server to pull the PDF decryption key from <a href="https://cloud.google.com/secret-manager">Secret Manager</a>, so I don&#8217;t have to deploy environment files, nor keep settings like that in version control, etc&#8230; But this meant a trickier flow of getting the FastAPI testing client up in a way that it worked without it talking to the cloud backends (and stalling, and failing&#8230;). Nothing that some good mocking cannot solve (says the person with hindsight).</p>



<p>For the cloud services part it meant mocking BigQuery connections, so that the test can actually pretend to &#8220;receive&#8221; an email all the way looking at the &#8220;database&#8221; and see the right information being there. Under the hood I&#8217;m using <a href="https://googleapis.dev/python/pandas-gbq/latest/index.html">pandas-gbq</a>, and thus it was interesting to look under the hood <a href="https://github.com/googleapis/python-bigquery-pandas/blob/685d1c39f709a58a9bf59fb1cec9474d3e3c03c0/tests/unit/conftest.py">for their tests</a>, borrowing some of them. Took a bit more time, but that&#8217;s working pretty well now. Still need to do some extra bits and pieces to do cover more of the workflow, but I&#8217;m already more confident about things working. Also, all this will be very useful on other projects that are interacting with BigQuery in any way (not just through Pandas).</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="618" height="404" src="https://gergely.imreh.net/blog/wp-content/uploads/2022/08/test-run-goodness.png" alt="" class="wp-image-2707" srcset="https://gergely.imreh.net/blog/wp-content/uploads/2022/08/test-run-goodness.png 618w, https://gergely.imreh.net/blog/wp-content/uploads/2022/08/test-run-goodness-500x327.png 500w" sizes="auto, (max-width: 618px) 100vw, 618px" /><figcaption>A test run that&#8217;s nice</figcaption></figure>



<p>Big evergreen lesson on testing: <strong>you have to write your code to be testable</strong>. Lots of code out there is not even not tested, but it&#8217;s even extremely difficult to actually test. This needs remembering in every development. Also, <strong>test writing never really stops</strong>, there&#8217;s always more thing to test for. And finally, can always try more advanced testing, such as using automated test case generation (e.g with <a href="https://hypothesis.readthedocs.io/en/latest/">hypothesis</a>), and fuzz testing (e.g. with <a href="https://gitlab.com/gitlab-org/security-products/analyzers/fuzzers/pythonfuzz">pythonfuzz</a>). The next frontier, right after I&#8217;ve implemented the currently skipped tests. And finally, remember that code coverage is not case coverage, so the goals should be maximizing the latter, while the former is just a potential proxy for it.</p>



<h2 class="wp-block-heading">Future outlook</h2>



<p>It would be nice to take this idea of financial data analysis further and add some actual dashboard (say deploying <a href="https://superset.apache.org/">Superset</a> somewhere which is excellent for this). It would help to get more information into the system as well, though, currently it&#8217;s very sparse. That would mean adding other financial sources, maybe if finding an API in the end, or doing a bit of &#8220;pragmatic execution&#8221; and do a CAPTCHA bypass (since I quickly checked that my credit card provider&#8217;s CAPTCHA is completely readable by <a href="https://tesseract-ocr.github.io/tessdoc/Home.html">Tesseract</a>, for example, so I <em>could</em> likely scrape things there if I really wanted.</p>



<p>I&#8217;m not holding my breath for having something like UK&#8217;s <a href="https://www.openbanking.org.uk/about-us/">Open Banking</a> here which enables apps like <a href="https://emma-app.com/">Emma</a> so all this is accessible for people who don&#8217;t want to code. But where&#8217;s the fun in that (for me)? :) (In fact there&#8217;s a lot of fun in open access APIs, so this would be the real way of doing it&#8230;)</p>



<p>Finally, it&#8217;s good to remember how easy it is to corrupt &#8220;production&#8221; data sets, but also with the right tools (like snapshots), some of that pressure can be less. There are always bugs, the question is how to mitigate their effect.</p>
<p>The post <a href="https://gergely.imreh.net/blog/2022/08/a-personal-finance-data-pipeline-project/">A personal finance data pipeline project</a> appeared first on <a href="https://gergely.imreh.net/blog">ClickedyClick</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://gergely.imreh.net/blog/2022/08/a-personal-finance-data-pipeline-project/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>100 Days to Offload WordPress Plugin</title>
		<link>https://gergely.imreh.net/blog/2022/07/100-days-to-offload-wordpress-plugin/</link>
					<comments>https://gergely.imreh.net/blog/2022/07/100-days-to-offload-wordpress-plugin/#comments</comments>
		
		<dc:creator><![CDATA[Gergely Imreh]]></dc:creator>
		<pubDate>Mon, 04 Jul 2022 05:44:17 +0000</pubDate>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[100DaysToOffload]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[wordpress plugin]]></category>
		<guid isPermaLink="false">https://gergely.imreh.net/blog/?p=2650</guid>

					<description><![CDATA[<p>Made a WordPress plugin to see how far off am I towards my 100 blogposts a year project.</p>
<p>The post <a href="https://gergely.imreh.net/blog/2022/07/100-days-to-offload-wordpress-plugin/">100 Days to Offload WordPress Plugin</a> appeared first on <a href="https://gergely.imreh.net/blog">ClickedyClick</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>In the course of pushing myself to write more on this blog, I&#8217;ve come across the <a href="https://100daystooffload.com/">#100DaysToOffload</a> project. It&#8217;s super simple: write a 100 blogposts in a year in your personal blog to unlock the achievement. It seems like gamification done to the right level, as it&#8217;s not to strenuous (&#8220;write every day&#8221; would likely fail before lift-off), and not too lax (100 blogpost are still quite a stretch to go!). Thus it looked like the right too to trick myself into doing the thing I already wanted.</p>



<p>On the other hand, I&#8217;m one for meta-games, especially when I have doubts whether I stand a chance in the game itself, thus came the idea of do <em>something</em> around 100DaysToOffload that might also result in a blogpost. Hence came the &#8220;Hundred Days to Offload&#8221; WordPress Plugin idea: get a bit of coding in, make something useful to see if the game has been &#8220;won&#8221;, an also get one (or more) write-ups out of it.</p>



<p>Spoiler alert: it&#8217;s working now, very barebones, but to the point&#8230; that there&#8217;s a long way to go.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="477" src="https://gergely.imreh.net/blog/wp-content/uploads/2022/07/hundred-days-to-offload-interface-1024x477.png" alt="Screenshot of the Hundred Days to Offload plugin in the WordPress admin interface." class="wp-image-2656" srcset="https://gergely.imreh.net/blog/wp-content/uploads/2022/07/hundred-days-to-offload-interface-1024x477.png 1024w, https://gergely.imreh.net/blog/wp-content/uploads/2022/07/hundred-days-to-offload-interface-500x233.png 500w, https://gergely.imreh.net/blog/wp-content/uploads/2022/07/hundred-days-to-offload-interface-768x358.png 768w, https://gergely.imreh.net/blog/wp-content/uploads/2022/07/hundred-days-to-offload-interface-1200x559.png 1200w, https://gergely.imreh.net/blog/wp-content/uploads/2022/07/hundred-days-to-offload-interface.png 1210w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption>How the Hundred Days to Offload plugin looks in practice (as of now).</figcaption></figure>



<p>In the process, that took a couple of days over the weekend, I&#8217;ve revisited PHP, that I used to &#8220;play&#8221; with for projects before, though haven&#8217;t done anything serious, nor made it part of my <a href="https://gergely.imreh.net/blog/tag/lotm/">Language of the Month series</a>, so far. It was still quite interesting to revisit with more mature eyes of e.g. how good projects look like in the Python ecosystem (where I spend most of my time), and whether lessons learned there are applicable here.</p>



<span id="more-2650"></span>



<h2 class="wp-block-heading">The Making of a WordPress Plugin</h2>



<p>The plugin itself is pretty straightforward: query WordPress for all the post that were published in the last 1 year, and count them. <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f9ee.png" alt="🧮" class="wp-smiley" style="height: 1em; max-height: 1em;" /> It could be slightly more complicated, if the goal would be more closely aligned to the &#8220;100 days to offload&#8221; name, that is if one would have to count <em>the number of unique days on which posts were made</em>, but let&#8217;s not move the goal-posts here.</p>



<p>Starting from the relevant <a href="https://developer.wordpress.org/plugins/">WordPress Handbook page</a> I could have an initial stab at laying out a plugin project structure, though I have to say, that the examples are not going too far in helping with that. This was augmented by a <a href="https://github.com/topics/wordpress-plugin">GitHub wordpress-plugin topic search</a>, where I could work from examples a lot better, and see some (maybe too many) best (or at least reasonable) practices.</p>



<p>This lead me to various ecosystem tooling such as </p>



<ul class="wp-block-list"><li><a href="https://getcomposer.org/">Composer</a>, the PHP dependency manager that I didn&#8217;t know before, and could very much relate to (with it&#8217;s prod/dev dependencies, scripts definitions, etc, reminding me of <a href="https://python-poetry.org/">Poetry</a> for Python a bit in spirit)</li><li><a href="https://phpstan.org/">PHPStan</a> static analysis tool, and its &#8220;fun times&#8221; with WordPress code (which can be fixed by various stub projects, etc),</li><li>all the &#8220;code standards&#8221; tools that do various fixes (while not being quite a linter and code formatted, but still being a little), for example <a href="https://github.com/WordPress/WordPress-Coding-Standards">wpcs</a>. This latter had a fun side effect that have to work from its cutting edge &#8220;develop&#8221; branch to work with PHP 8.1 that I had at hand, so definitely learned through that a few Composer quirks.</li></ul>



<p>In the end I had my little snippet of code, run through all these codes, fixed up tabs vs spaces, docs strings, types for return values, dependencies, <em>actual</em> bugs of wrong input types to various PHP functions, and also some best practices (which might or might not apply to my little code). It&#8217;s a rabbit hole that could go a lot deeper, though, so cutting a release version at a point. The rest goes <a href="https://github.com/imrehg/hundred-days-to-offload-wordpress/issues">into an issue tracker</a> to pick up one day.</p>



<p>And now, with an MVP (minimum viable plugin;) at hand, I&#8217;ve <a href="https://wordpress.org/plugins/developers/add/">submitted</a> for review. That&#8217;s just the cherry on the top, or start of new problems with a project to support. Either way I can use the plugin checked out with git just fine.</p>



<figure class="wp-block-image size-large"><img decoding="async" src="https://gergely.imreh.net/blog/wp-content/uploads/2022/07/Screenshot-2022-07-04-at-11.09.18-1024x484.png" alt="" class="wp-image-2651"/><figcaption>Plugin submission, <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f91e.png" alt="🤞" class="wp-smiley" style="height: 1em; max-height: 1em;" /> to see what happens</figcaption></figure>



<p>I&#8217;ve definitely picked up <em>a tiny bit</em> of PHP for now, even if mostly accidentally, and likely full of bugs and bad practices. It&#8217;s still interesting, and a learning experience. For example data handling is a source of many, various pains in all languages I&#8217;ve across so far. The PHP way (or WordPress way?) of object orientation is also just scratched on the surface and accepted as it goes, but not from a point of solid understanding.</p>



<h2 class="wp-block-heading">Looking to the future</h2>



<p>From the plugin&#8217;s side it would be good to add some style and looks, as it&#8217;s super dummy and bare bones. But how should it look? Time to learn a bit of design and/or run some user testing? The mixing of HTML and code is also particularly mind-bending (or awkward, or intriguing, or&#8230;), I would need to look where to set the right boundaries for that, as there could be many.</p>



<p>Adding CI/CD as well, so definitely various PHP versions can be tested (seems easy), and potentially various WordPress versions as well (seems a lot more hairy) could be a practice and baseline.</p>



<p>Adding some settings to change would help me to learn more plugin development, though this particular plugin might not benefit a lot from it.</p>



<p>Work out how to do proper translations / i18n would be probably pretty solid benefit as well, and that needs a lot more digging (variable texts are not straightforward to translate).</p>



<p>Finally, all of these improvements might also just make a few extra blogposts to get towards my 100 Days to Offload. <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/270d.png" alt="✍" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<p>The post <a href="https://gergely.imreh.net/blog/2022/07/100-days-to-offload-wordpress-plugin/">100 Days to Offload WordPress Plugin</a> appeared first on <a href="https://gergely.imreh.net/blog">ClickedyClick</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://gergely.imreh.net/blog/2022/07/100-days-to-offload-wordpress-plugin/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Creating a Prometheus metrics exporter for a 4G router</title>
		<link>https://gergely.imreh.net/blog/2022/06/creating-a-prometheus-metrics-exporter-for-a-4g-router/</link>
					<comments>https://gergely.imreh.net/blog/2022/06/creating-a-prometheus-metrics-exporter-for-a-4g-router/#respond</comments>
		
		<dc:creator><![CDATA[Gergely Imreh]]></dc:creator>
		<pubDate>Tue, 14 Jun 2022 03:25:24 +0000</pubDate>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[grafana]]></category>
		<category><![CDATA[prometheus]]></category>
		<category><![CDATA[python]]></category>
		<guid isPermaLink="false">https://gergely.imreh.net/blog/?p=2628</guid>

					<description><![CDATA[<p>Debugging 4G router network connectivity issues by scraping its metrics and making some pretty graphs. Experimenting with loads of new tech that I didn't get to use in anger before.</p>
<p>The post <a href="https://gergely.imreh.net/blog/2022/06/creating-a-prometheus-metrics-exporter-for-a-4g-router/">Creating a Prometheus metrics exporter for a 4G router</a> appeared first on <a href="https://gergely.imreh.net/blog">ClickedyClick</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Recently I begun fully remote working from home, with the main network connectivity provided by a 4G mobile router. Very soon I experienced patchy connectivity, not the greatest thing when you are on video calls for half of each day. What does one do then (if not just straight replacing the whole setup with a wired ISP, if possible), other than monitor what&#8217;s going on and try to debug the issues?</p>



<p>The router I have is a less-common variety, an Alcatel Linkhub HH441 (can&#8217;t even properly link to on the manufacturer&#8217;s site, just on online retail stores). At least as it should, it does have a web front-end, that one can poke around in, and gather metrics from &#8211; of course in an automatic way.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="800" height="553" src="https://gergely.imreh.net/blog/wp-content/uploads/2022/05/linkhub_product.jpg" alt="" class="wp-image-2629" srcset="https://gergely.imreh.net/blog/wp-content/uploads/2022/05/linkhub_product.jpg 800w, https://gergely.imreh.net/blog/wp-content/uploads/2022/05/linkhub_product-500x346.jpg 500w, https://gergely.imreh.net/blog/wp-content/uploads/2022/05/linkhub_product-768x531.jpg 768w" sizes="auto, (max-width: 800px) 100vw, 800px" /><figcaption>The Alcatel HH41 LinkHub router that I had at hand to use</figcaption></figure>



<p>Looking at the router&#8217;s web interface, and checking the network activity through the browsers&#8217; network monitor (<a href="https://firefox-source-docs.mozilla.org/devtools-user/index.html#network-monitor">Firefox</a>, <a href="https://developer.chrome.com/docs/devtools/network/">Chrome</a>), the frontend&#8217;s API calls showed up, so I could collect a few that requested different things like radio receiving metrics, bandwidth usage, uptime, and so on&#8230; From here we are off to the races setting up our monitoring infrastructure, along these pretty standard lines:</p>



<ul class="wp-block-list"><li>Set up a <a href="https://prometheus.io/docs/instrumenting/exporters/">Prometheus metrics exporter</a>, pulling data from the router&#8217;s internal API (the same way the web interface does it)</li><li>Spin up a <a href="https://prometheus.io/">Prometheus</a> + <a href="https://grafana.com/">Grafana</a> interface to actually monitor, alert on, and debug any metrics</li></ul>



<span id="more-2628"></span>



<h2 class="wp-block-heading">Metrics Exporter</h2>



<p>Given that I&#8217;m mostly working with Python, using the existing <a href="https://github.com/prometheus/client_python">Prometheus Python client</a> was an easy choice, in particular using their internal <a href="https://github.com/prometheus/client_python#http">HTTP exporter</a> to get started quickly. It was relatively straightforward to turn many of the metrics into various <a href="https://prometheus.io/docs/concepts/metric_types/#gauge">gauges</a> (radio reception metrics, bandwidth used, &amp;c.), though some were naturally <a href="https://github.com/prometheus/client_python#info">info fields</a>, such as mobile network name and cell ID. This latter would be very useful as my hunch was cell hopping by the router is what&#8217;s mainly affecting my network quality.</p>



<p>After some poking around I&#8217;ve also realised, that the API exposed is just <a href="https://www.jsonrpc.org/">JSON-RPC</a> (although the router&#8217;s backend doesn&#8217;t seem implement everything in there, e.g. there&#8217;s no <a href="https://www.jsonrpc.org/specification#batch">batch</a>), which made a lot of things clearer, and potentially easier to use.</p>



<p>In the end, I&#8217;ve ended up with one class to do all the metrics gathering from a couple of JSON-RPC methods, working relatively robustly. The authentication was simplified very much: most need an auth token that can be extracted by manually observing some requests (more on this later) and some need a <a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referer">referrer header</a> for the request to pretend to be coming from the admin console.</p>



<p>The resulting code is on GitHub: <a href="https://github.com/imrehg/linkhub_prometheus_exporter">imrehg / linkhub_prometheus_exporter</a>, and should be a full-featured server with most (though probably not all) the metrics available in the admin console as well.</p>



<h2 class="wp-block-heading">Monitoring</h2>



<p>With the metrics exporter running, I used a <a href="https://docs.docker.com/compose/">Docker Compose</a>-based <a href="https://github.com/vegasbrianc/prometheus">Prometheus + Grafana stack</a> locally to have everything together, just adding an extra &#8220;linkhub&#8221; task in Prometheus to pull the data periodically, and a new dashboard in Grafana to have a quick overview.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="602" src="https://gergely.imreh.net/blog/wp-content/uploads/2022/05/grafana_screenshot1-1024x602.png" alt="Grafana view of some of the reception metrics" class="wp-image-2630" srcset="https://gergely.imreh.net/blog/wp-content/uploads/2022/05/grafana_screenshot1-1024x602.png 1024w, https://gergely.imreh.net/blog/wp-content/uploads/2022/05/grafana_screenshot1-500x294.png 500w, https://gergely.imreh.net/blog/wp-content/uploads/2022/05/grafana_screenshot1-768x451.png 768w, https://gergely.imreh.net/blog/wp-content/uploads/2022/05/grafana_screenshot1-1536x902.png 1536w, https://gergely.imreh.net/blog/wp-content/uploads/2022/05/grafana_screenshot1-2048x1203.png 2048w, https://gergely.imreh.net/blog/wp-content/uploads/2022/05/grafana_screenshot1-1200x705.png 1200w, https://gergely.imreh.net/blog/wp-content/uploads/2022/05/grafana_screenshot1-1980x1163.png 1980w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption>Grafana view of some of the reception metrics</figcaption></figure>



<p>I also went a bit overboard and added some extra bits and pieces, like coloured regions for the signal metrics to show what&#8217;s bad / acceptable / good / excellent or so, based on <a href="https://www.digi.com/support/knowledge-base/understanding-lte-signal-strength-values">some scouting</a>, making it clearer when things are good or not good.</p>



<p>I also tried to use a bit more of Grafana&#8217;s tooling (not a lot, but a bit more), so added some different sections for signal quality and network metrics, as well as a running average on some of the noisy metrics. </p>



<h2 class="wp-block-heading">Lessons learned</h2>



<p>Learned a bunch of things as this was the first time I used, from scratch, many of the tools here. The very first one being: how to choose the right Prometheus metrics for various data streams? Now I see how does it look like in practice, planning for a metric that needs to be monitored from the very early stage. There are fewer varieties of metrics that I&#8217;ve expected, and while there&#8217;s a lot of derivative stuff to make it a lot more useful, it&#8217;s not that everything that one imagines can be made to work.</p>



<p>Used Poetry here  more than previously, and set up <a href="https://github.com/mtkennerly/poetry-dynamic-versioning">poetry-dynamic-versioning plugin</a> (as a candidate competitor to <a href="https://github.com/pypa/setuptools_scm">setuptools-scm</a>). That meant also using poetry plugins and a beta Poetry release at this stage. It’s not bad, but sooo many gotchas in the process, and still have to figure out what would be a good reusable template for projects using these. (including __version__ variables, etc).</p>



<p>Figured out how to do good CI Docker image builds with libraries that rely on git for versioning, fortunately <a href="https://github.com/pypa/setuptools_scm#usage-from-docker">setuptools_scm did the work for us</a>: bind mount of .git in the specific build step. I think in CI/CD all this reliance of repo data being available can still make things a bit trickier, but something&#8217;s gotta give, and it&#8217;s not much extra compared to the rest of the things.</p>



<p>Learned a bit about JSON-RPC (and how the router might or might not be fully compliant). Not sure if I&#8217;d go with that for any future project myself, but good to be aware of it, and potentially looking at its presence in other routers or interfaces&#8217; communications channels.</p>



<p>Chance to use some Python 3.10-based features (match) and hit/fix some of <a href="https://github.com/actions/setup-python/issues/160">GitHub actions related issues with 3.10</a>:way to go libraries that convert 3.10 to “3.1&#8243; because it’s a number so let’s round it, right? Or actually way to go libraries/YAML to allow both &#8216;x.y&#8217; and x.y forms (quoted and unquoted), and the former would have been the correct form all the time, but people generally go with the latter to save a few keypresses. It&#8217;s subtle, but experience is expecting the subtleties and the reasons for them arising.</p>



<p>Seen how <a href="http://mypy-lang.org/">mypy</a> can actually benefit the coda quality: while trying to fix all the reported issues actually found stuff that was clear benefit and it’s coming not from adding all the type hints (that’s good, but baseline), rather than being smart where it complains and think about what’s the underlying issue (e.g. patterns of getting values out of dicts where there might not be result, exhaustive matching of match and return values of functions, etc…)</p>



<p>The resulting Docker image is north of 1GB due to Python, and that&#8217;s not great considering that it doesn&#8217;t do <em>that much</em> work. Writing/rewriting this whole thing in Go could be interesting and would be useful learning experience (or another compiled language, I guess, but Prometheus itself is written in Go, so there&#8217;s a connection). One step at a time, projects written in Python are useful proof-of-concept to compare other stuff against later, so it was well.</p>



<p>Having said that, I&#8217;ve seen the best practices listed <a href="https://prometheus.io/docs/instrumenting/writing_exporters/">when writing Prometheus exporters</a>, and given the current environment, I couldn&#8217;t apply all the best practices. <a href="https://prometheus.io/docs/instrumenting/writing_exporters/#scheduling">For example</a>: &#8220;Metrics should only be pulled from the application when Prometheus scrapes them, exporters should not perform scrapes based on their own timers.&#8221; The official Prometheus Python Exporter on the other hand seems to need to use exactly that sort of &#8220;while True&#8221; loop to keep getting/storing metrics, instead if running on demand. There might be a more subtle pattern to do on-demand work (which I see to be more correct), but I need to find it.</p>



<p>So what have I learned about the actual network issues? Most of the instability seemed to be correlated with switching to specific cell towers (based on cell IDs). Certain cell towers would pretty stable, and on some of the days the router was switching between towers, and that&#8217;s when most of my online calls were pretty futile.</p>



<p>Finally, I did think a lot about the adage that &#8220;something that isn&#8217;t worth doing isn&#8217;t worth doing well.&#8221; On the other hand there&#8217;s no kill like overkill, so here we are&#8230;</p>



<h2 class="wp-block-heading">Future development</h2>



<p>Compared to other projects I&#8217;ve done, this might be lighter maintenance, given that it&#8217;s sorta done for the moment (except if others start to use it and need other metrics, for example). Otherwise the Docker-based deployment and poetry.lock&#8217;d dependencies make bit-rot a bit slower, hopefully. In the meantime, I&#8217;ve switched to a wired connection, so unlikely to need this project much, but it could be that much of this will be repurposed for other monitoring projects.</p>
<p>The post <a href="https://gergely.imreh.net/blog/2022/06/creating-a-prometheus-metrics-exporter-for-a-4g-router/">Creating a Prometheus metrics exporter for a 4G router</a> appeared first on <a href="https://gergely.imreh.net/blog">ClickedyClick</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://gergely.imreh.net/blog/2022/06/creating-a-prometheus-metrics-exporter-for-a-4g-router/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>How not to start with machine learning</title>
		<link>https://gergely.imreh.net/blog/2019/02/how-not-to-start-with-machine-learning/</link>
					<comments>https://gergely.imreh.net/blog/2019/02/how-not-to-start-with-machine-learning/#comments</comments>
		
		<dc:creator><![CDATA[Gergely Imreh]]></dc:creator>
		<pubDate>Fri, 01 Feb 2019 17:51:25 +0000</pubDate>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Jetson TX2]]></category>
		<category><![CDATA[Machine learning]]></category>
		<category><![CDATA[PyTorch]]></category>
		<guid isPermaLink="false">https://gergely.imreh.net/blog/?p=2482</guid>

					<description><![CDATA[<p>I've tried to teach computers to play Connect4, and they didn't like it one bit.</p>
<p>The post <a href="https://gergely.imreh.net/blog/2019/02/how-not-to-start-with-machine-learning/">How not to start with machine learning</a> appeared first on <a href="https://gergely.imreh.net/blog">ClickedyClick</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>I&#8217;m a technical and scientific person. I&#8217;ve done some <a href="https://gergely.imreh.net/blog/2012/01/adventures-into-online-learning/">online courses</a> on machine learning, read enough articles about different machine learning projects, I go through the discussions of those projects on <a href="https://news.ycombinator.com">Hacker News</a>, and kept a bunch of ideas what would be cool for the machines to actually learn. I&#8217;m in the right place to actually do some project, right? Right? <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f6a8.png" alt="🚨" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Wrong, the Universe says no&#8230;</p>



<p>This is the story of how I&#8217;ve tried one particular project that seemed easy enough, but leading me to go back a few (a bunch of) steps, and rethink my whole approach.</p>



<p>I bet almost everyone in tech (and a lot of people beyond) heard of <a href="https://deepmind.com/research/alphago/">AlphaGo</a>, Deepmind&#8217;s program to play the game of Go beyond what humans can do. That has evolved, and the current state of the art is <a href="https://deepmind.com/blog/alphazero-shedding-new-light-grand-games-chess-shogi-and-go/">Alpha Zero</a>, which takes the approach of starting from scratch, just the rules of the game, and applying self-play, can master games like Go to an even higher level than the previous programmatic champion after relatively brief training (and beating AlphaGo and it&#8217;s successor AlphaGo Zero), but also apply to other games (such as chess and <a href="https://en.wikipedia.org/wiki/Shogi">shogi</a>). AlphaZero&#8217;s self-learning (and <a href="https://en.wikipedia.org/wiki/Unsupervised_learning">unsupervised learning</a> in general) fascinates me, and I was excited to see that someone published their open source AlphaZero implementation: <a href="https://github.com/suragnair/alpha-zero-general/">alpha-zero-general</a>. That project applies a smaller version of AlphaZero to a number of games, such as <a href="https://en.wikipedia.org/wiki/Reversi">Othello</a>, <a href="https://en.wikipedia.org/wiki/Tic-tac-toe">Tic-tac-toe</a>, <a href="https://en.wikipedia.org/wiki/Connect_Four">Connect4</a>, <a href="https://en.wikipedia.org/wiki/Gomoku">Gobang</a>. My plan was to learn by adding some features and training some models for some of the games (learn by doing). That sounds much easier to say than to do, and unravelled pretty quickly (but probably not as quickly as it should have been).</p>



<span id="more-2482"></span>



<p>I&#8217;ve picked the game Connect4, because a) I used to play that long time ago, b) feels like a relatively simple game, while still interesting, c) the repository didn&#8217;t have a pre-trained model for the  <a href="https://pytorch.org/">PyTorch</a> platform, that I wanted to try.</p>



<figure class="wp-block-image is-resized"><img loading="lazy" decoding="async" src="https://gergely.imreh.net/blog/wp-content/uploads/2019/02/3e1d2a8ca40cafc455663f79cf66125b98886a70-min.jpg" alt="Connect 4" class="wp-image-2486" width="1000" height="1000" srcset="https://gergely.imreh.net/blog/wp-content/uploads/2019/02/3e1d2a8ca40cafc455663f79cf66125b98886a70-min.jpg 1000w, https://gergely.imreh.net/blog/wp-content/uploads/2019/02/3e1d2a8ca40cafc455663f79cf66125b98886a70-min-150x150.jpg 150w, https://gergely.imreh.net/blog/wp-content/uploads/2019/02/3e1d2a8ca40cafc455663f79cf66125b98886a70-min-500x500.jpg 500w, https://gergely.imreh.net/blog/wp-content/uploads/2019/02/3e1d2a8ca40cafc455663f79cf66125b98886a70-min-768x768.jpg 768w" sizes="auto, (max-width: 1000px) 100vw, 1000px" /><figcaption>Connect4, courtesy of <a href="https://shop.hasbro.com/en-us/product/connect-4-game:80FB5BCA-5056-9047-F5F4-5EB5DF88DAF4">Hasbro</a></figcaption></figure>



<p>PyTorch was the choice, as it works both on GPUs (as the preferred workhorses of machine learning projects) and also on my laptop that only has a CPU to use.</p>



<h3 class="wp-block-heading">The unraveling</h3>



<p>Getting started was easy enough. The neural network setup seemed to be pretty much the same between the different games, so I&#8217;ve just copied and adapted another PyTorch setup to Connect 4. Run it briefly on my laptop, and it was doing things, it was playing games. The training takes place in 3 phases: first generating some example games (from random valid moves, or existing model, I think); next train the model on those example games to recognize better what it takes to win; finally the new model is pitted against the previous one, and either accepted or rejected as the basis for further training, based on the win-draw-lose percentages.</p>



<p>I&#8217;ve trained for a <g class="gr_ gr_8 gr-alert gr_gramm gr_inline_cards gr_run_anim Punctuation only-del replaceWithoutSep" id="8" data-gr-id="8">while,</g> and then played against the model to see how it feels. Seemed sensible enough, but of course, since I don&#8217;t play the game too well, so didn&#8217;t know what to expect.</p>



<p>I&#8217;ve started to look for some better Connect4-player software that I can pit the trained model against, when realized that it is an already solved game, with a perfect strategy! You can see either <a href="https://tromp.github.io/c4.html">Expert Play in Connect-Four</a> by James D. Allen, or this entire masters thesis, <a href="http://www.informatik.uni-trier.de/~fernau/DSL0607/Masterthesis-Viergewinnt.pdf">A Knowledge-based Approach of Connect-Four</a> by Victor Allis. I &#8230; am yet to read either, but since I found an online implementation of the <a href="https://connect4.gamesolver.org/">Connect 4 Solver</a>, I knew that will help me to test how well the trained model work. Since the game is solved, and the first player will always win, that should help simplify and the training a bit, right? For example, I would know when the perfect strategy is achieved: when in the post-training it consistently gets 50% wins, 50% loss, and 0% draw, then it plays perfectly.</p>



<p>Trying to validate this hunch, I was training it on my laptop, but the training times went up tremendously as the number example games are increased in each iteration. My laptop generated example games fast enough, but then the training was getting slower and slower. Needed to search for an alternative. Fortunately, I had access to an idle <a href="https://developer.nvidia.com/embedded/develop/hardware">NVIDIA Jetson TX2</a> machine, which is more-or-less a 64-bit ARM machine with some pretty decent GPU with plenty of <a href="https://www.geforce.co.uk/hardware/technology/cuda">CUDA</a> power attached. Was designed for machine learning, and should be perfect (or rather overkill?) for my application.</p>



<p>Setting up wasn&#8217;t too difficult, though I think the <g class="gr_ gr_166 gr-alert gr_spell gr_inline_cards gr_run_anim ContextualSpelling" id="166" data-gr-id="166">pytorch</g> module has built for a <g class="gr_ gr_216 gr-alert gr_spell gr_inline_cards gr_run_anim ContextualSpelling" id="216" data-gr-id="216">whiiiiiile</g>, so I saved it as a Python <a href="https://pythonwheels.com/">wheel</a> to make it quicker to install next time. Then started the whole training process afresh the TX2. The second, training step was indeed a lot quicker (30-60 minutes instead of 4-8 hours), though now since the ARM core of the device is much slower than my X86 laptop, the first, game generation step and the last, tournament phase were a lot slower (an hour instead 10-15 minutes if I recall). Overall it&#8217;s still a win, so could run a handful of iterations in the process each day. It was the winter holidays, so there were plenty of days for the machine to train.</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="1024" height="241" src="https://gergely.imreh.net/blog/wp-content/uploads/2019/02/Screenshot_2019-02-01_16-56-44-min-1024x241.png" alt="Console log of training the model on the Jetson TX2" class="wp-image-2488" srcset="https://gergely.imreh.net/blog/wp-content/uploads/2019/02/Screenshot_2019-02-01_16-56-44-min-1024x241.png 1024w, https://gergely.imreh.net/blog/wp-content/uploads/2019/02/Screenshot_2019-02-01_16-56-44-min-500x118.png 500w, https://gergely.imreh.net/blog/wp-content/uploads/2019/02/Screenshot_2019-02-01_16-56-44-min-768x181.png 768w, https://gergely.imreh.net/blog/wp-content/uploads/2019/02/Screenshot_2019-02-01_16-56-44-min-1568x370.png 1568w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption>Keep training, little computer<br></figcaption></figure>



<p>What I ended up seeing is a kinda static phase. Almost all <g class="gr_ gr_221 gr-alert gr_gramm gr_inline_cards gr_run_anim Grammar multiReplace" id="221" data-gr-id="221">draws</g> in the tournament phase, with very few wins. There were many iterations with nothing really changing, new models being rejected for the lack of wins. Then pitting the model against the solver, it starts off well enough, for about 4-5 moves, and after that, the algorithm makes a move that is impossible to recover from&#8230;</p>



<figure class="wp-block-image"><img loading="lazy" decoding="async" width="1024" height="668" src="https://gergely.imreh.net/blog/wp-content/uploads/2019/02/Screenshot_2019-02-01_16-40-14-min-1024x668.png" alt="Screenshot of the Connect 4 solver website with a game that Red cannot win anymore, even though with perfect strategy Red would always win." class="wp-image-2490" srcset="https://gergely.imreh.net/blog/wp-content/uploads/2019/02/Screenshot_2019-02-01_16-40-14-min-1024x668.png 1024w, https://gergely.imreh.net/blog/wp-content/uploads/2019/02/Screenshot_2019-02-01_16-40-14-min-500x326.png 500w, https://gergely.imreh.net/blog/wp-content/uploads/2019/02/Screenshot_2019-02-01_16-40-14-min-768x501.png 768w, https://gergely.imreh.net/blog/wp-content/uploads/2019/02/Screenshot_2019-02-01_16-40-14-min-1568x1022.png 1568w, https://gergely.imreh.net/blog/wp-content/uploads/2019/02/Screenshot_2019-02-01_16-40-14-min.png 1868w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /><figcaption>Playing against the <a href="https://connect4.gamesolver.org/">Solver</a>. Red always wins with perfect strategy.</figcaption></figure>



<p>I was trying to change the code a bit, based on some quite interesting issues opened on the original repo. For example, there&#8217;s <a href="https://github.com/suragnair/alpha-zero-general/issues/95">one asking</a> why the <a href="https://en.wikipedia.org/wiki/Monte_Carlo_tree_search">Monte Carlo Tree Search</a> is set up as it is, and whether another setup would help it train faster? (Faster is good, faster to see both successes and failures in the whole training process. Can&#8217;t waste time, when everything takes hours!). Then there&#8217;s <a href="https://github.com/suragnair/alpha-zero-general/issues/88">another question</a> regarding the models ending up in draws all the time (that&#8217;s familiar?). Or this very straightforward &#8220;<a href="https://github.com/suragnair/alpha-zero-general/issues/96">Connect4 Not <g class="gr_ gr_856 gr-alert gr_spell gr_inline_cards gr_disable_anim_appear ContextualSpelling ins-del multiReplace" id="856" data-gr-id="856"><g class="gr_ gr_10 gr-alert gr_spell gr_inline_cards gr_disable_anim_appear ContextualSpelling ins-del multiReplace" id="10" data-gr-id="10">Learing</g></g></a>&#8220;, which is obviously relevant to my interests. All are open and unsolved questions, so I went to look a bit deeper, that prompted <em>even more</em> questions.</p>



<p>Why the implementation uses its neural network setup as it does, and does it work since it is much simpler than the original AlphaZero, as mentioned in the <a href="https://github.com/suragnair/alpha-zero-general/issues/96">code author&#8217;s blog</a>? What do the different neural network designs mean, and how can I see quickly if I&#8217;ve set up one that has the potential to learn correctly or it&#8217;s a dummy? How does the AlphaZero algorithm actually work? Is it all tied down properly, or some parameters/implementations are not clearly defined in the papers, as the issues I&#8217;ve mentioned above hint? How does PyTorch work and how do I use properly (and optimize it, much further down the line)?</p>



<p>You might say these questions are very basic, fundamental, and that&#8217;s indeed the case. One misses the fundamentals in the hubris of jumping into a project that just because I have a general birds-eye view of the problem and some code of an unknown quality that someone&#8217;s written. It&#8217;s not all set and garden path to some sweet easy wins. I am not writing off that two weeks of experimentations as waste, but do need to change the approach.</p>



<h3 class="wp-block-heading">Now what?</h3>



<p>At this point going back to the basics sounds like the right way, and with more humble, step by step learning build up the skills to make more sense of the whole project.</p>



<ul class="wp-block-list"><li>Get to know PyTorch, and make some working examples building on the tutorials (or get inspired by them). Looking at some online courses like <a href="https://www.edx.org/course/deep-learning-with-python-and-pytorch">the one by IBM</a> shared on edX. Work until the tools are getting comfortable.</li><li>Read the AlphaZero papers (the <a href="https://arxiv.org/abs/1712.01815">original</a>, and the follow-up linked from <a href="https://deepmind.com/blog/alphazero-shedding-new-light-grand-games-chess-shogi-and-go/">their website</a>), as well as explore around the topic following their references and articles referring to them</li><li>Properly review the source code of the <a href="https://github.com/suragnair/alpha-zero-general">open source implementation</a> I was using, and the accompanying <a href="http://web.stanford.edu/~surag/posts/alphazero.html">tutorial</a>. Not just skim and pull code blindly.</li><li>Bonus, find some higher <g class="gr_ gr_1122 gr-alert gr_gramm gr_inline_cards gr_disable_anim_appear Grammar only-ins replaceWithoutSep" id="1122" data-gr-id="1122">level</g> inspiration for neural network design (as getting the network right is the big part of the whole thing, that&#8217;s how it look). Sources like <a href="http://www.asimovinstitute.org/neural-network-zoo/">The Neural Network Zoo</a> by the Asimov Institute, which shows different networks for different kinds of tasks.</li></ul>



<p>This should get me to a point where the original plan has some chance of succeeding. And if it sounds like a common-sense plan, it is because yeah, maybe that&#8217;s what a lot of occasions need, a bit more common sense&#8230; I wonder if it&#8217;s a radical thought, but it took me a while to get to that. <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f915.png" alt="🤕" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>



<p>In the future should also probably compare the different machine learning platforms as well, <a href="https://www.tensorflow.org">TensorFlow</a>, <a href="https://keras.io/">Keras</a>, <a href="https://mxnet.apache.org/">MXNet</a>, maybe there are other ones as well, and run some sweet-sweet learning in the cloud (have some spare credits here and there, I wonder if they will expire by the time I&#8217;m done with my &#8220;common sense plan&#8221;).</p>



<p>I wonder though if others also run into a wall like me, and if did, what did they do? Is there any other lesson in human learning that this machine learning story can provide?</p>
<p>The post <a href="https://gergely.imreh.net/blog/2019/02/how-not-to-start-with-machine-learning/">How not to start with machine learning</a> appeared first on <a href="https://gergely.imreh.net/blog">ClickedyClick</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://gergely.imreh.net/blog/2019/02/how-not-to-start-with-machine-learning/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Home Automation Mix-and-Match</title>
		<link>https://gergely.imreh.net/blog/2016/04/home-automation-mix-and-match/</link>
					<comments>https://gergely.imreh.net/blog/2016/04/home-automation-mix-and-match/#respond</comments>
		
		<dc:creator><![CDATA[Gergely Imreh]]></dc:creator>
		<pubDate>Sun, 10 Apr 2016 10:58:52 +0000</pubDate>
				<category><![CDATA[Maker]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Home Assistant]]></category>
		<category><![CDATA[home automation]]></category>
		<category><![CDATA[IoT]]></category>
		<category><![CDATA[Olimex]]></category>
		<category><![CDATA[OLinuXino Lime2]]></category>
		<category><![CDATA[Seeed Studio]]></category>
		<category><![CDATA[Wio Link]]></category>
		<guid isPermaLink="false">https://gergely.imreh.net/blog/?p=2245</guid>

					<description><![CDATA[<p>Building a presence alert home automation system with Seeed Studio's Wio Link, Home Assistant, a DD-WRT router, and an Olimex Lime2 ARM server.</p>
<p>The post <a href="https://gergely.imreh.net/blog/2016/04/home-automation-mix-and-match/">Home Automation Mix-and-Match</a> appeared first on <a href="https://gergely.imreh.net/blog">ClickedyClick</a>.</p>
]]></description>
										<content:encoded><![CDATA[<p>This week I got a <a href="http://www.seeedstudio.com/wiki/Wio_Link">Wio Link</a> prototype from a friend at <a href="https://www.seeedstudio.com/">Seeed Studio</a>. It is an <a href="https://en.wikipedia.org/wiki/ESP8266">ESP8266</a>-based little Internet of Things board with 6 Grove connectors for easy device connectivity, wifi networking, and controlled over an app &amp; the Internet. For a quick project I wanted to hook it up with Home Assistant, an open source home automation platform that I read a lot about lately. The main focus was to have a first impression of both parts, and build up some experience for future, more serious projects.</p>
<p>The target solution: <em>light up an LED if a particular person is at home location</em>. Sort of a basic alarm system, though notice that the location of the LED was not mentioned &#8211; it can actually be anywhere in the world, as long as there&#8217;s Internet connectivity.</p>
<p>I&#8217;ve used the <a href="http://www.seeedstudio.com/wiki/Wio_Link">Wio Link</a>, a <a href="http://www.seeedstudio.com/wiki/Grove_-_LED_Socket_Kit">Grove LED light</a>, an <a href="https://www.olimex.com/Products/OLinuXino/A20/A20-OLinuXIno-LIME2/open-source-hardware">Olimex OLinuXino Lime2 board</a> running <a href="http://archlinuxarm.org/">ArchLinux</a> for the server, and a <a href="http://www.buffalotech.com/products/wireless/open-source-dd-wrt/airstation-highpower-n450-gigabit-dd-wrt-wireless-router">Buffalo router</a> with <a href="http://www.dd-wrt.com/site/index">DD-WRT</a> system installed.</p>
<h2>Wio Link</h2>
<p>Wio Link was introduced in <a href="https://www.kickstarter.com/projects/seeed/wio-link-3-steps-5-minutes-build-your-iot-applicat">Seeed&#8217;s Kickstarter campaign</a>, where they have raised more than 8x of their original target. It looks like a neat little board, and was happy to try out when I got my hands on one.</p>
<p>Their <a href="http://www.seeedstudio.com/wiki/Wio_Link">wiki page</a> has quite a bit of information, so it was easy to get started. Connect to power, hold down the configure button till the LED lights up in a &#8220;breathing&#8221; pattern, connect through <a href="https://play.google.com/store/apps/details?id=cc.seeed.iot.ap">their Wio Link app</a>, set up the wireless network settings and so on. Once connected, can define what kind of devices are attached to the board, and it looks like most of <a href="http://www.seeedstudio.com/wiki/Grove_System">Grove devices</a> are represented there. I only had a Grove LED at hand, so added it (&#8220;Generic Digital Output&#8221;), updated it, which created a new firmware and pushed onto the device.</p>
<p><figure id="attachment_2248" aria-describedby="caption-attachment-2248" style="width: 604px" class="wp-caption aligncenter"><a href="https://gergely.imreh.net/blog/wp-content/uploads/2016/04/WioLink.png" rel="attachment wp-att-2248"><img loading="lazy" decoding="async" class="size-large wp-image-2248" src="https://gergely.imreh.net/blog/wp-content/uploads/2016/04/WioLink-1024x607.png" alt="Wio Link setup process (left to right): add device, update firmware, check status" width="604" height="358" srcset="https://gergely.imreh.net/blog/wp-content/uploads/2016/04/WioLink-1024x607.png 1024w, https://gergely.imreh.net/blog/wp-content/uploads/2016/04/WioLink-500x296.png 500w, https://gergely.imreh.net/blog/wp-content/uploads/2016/04/WioLink-768x455.png 768w" sizes="auto, (max-width: 604px) 100vw, 604px" /></a><figcaption id="caption-attachment-2248" class="wp-caption-text">Wio Link setup process (left to right): add device, update firmware, check status</figcaption></figure></p>
<p>The first update took a couple of minutes, but it&#8217;s pretty straightforward. The device then also has an API link, which brings up a web page with all the options to query, control, and reset the attached accessories (in my case that&#8217;s the one digital output).</p>
<p><span id="more-2245"></span></p>
<p>The API is pretty simple and usable, though definitely not perfect (will come back to this).</p>
<p><a href="https://gergely.imreh.net/blog/wp-content/uploads/2016/04/WioLinkAPI.png" rel="attachment wp-att-2252"><img loading="lazy" decoding="async" class="aligncenter size-full wp-image-2252" src="https://gergely.imreh.net/blog/wp-content/uploads/2016/04/WioLinkAPI.png" alt="WioLinkAPI" width="941" height="800" srcset="https://gergely.imreh.net/blog/wp-content/uploads/2016/04/WioLinkAPI.png 941w, https://gergely.imreh.net/blog/wp-content/uploads/2016/04/WioLinkAPI-500x425.png 500w, https://gergely.imreh.net/blog/wp-content/uploads/2016/04/WioLinkAPI-768x653.png 768w" sizes="auto, (max-width: 941px) 100vw, 941px" /></a></p>
<p>Since manual switching the light on and off worked like the charm, the next step was to enable automatic switching by the presence detection within the home automation system.</p>
<h2>Home Assistant</h2>
<p><a href="http://home-assistant.io/">Home Assistant</a> is an open source home automation system written in Python. There&#8217;s a lot to like about it, and a lot of people are checking it out since a number of other, closed system providers are <a href="https://home-assistant.io/blog/2016/04/05/your-hub-should-be-local-and-open/">shutting down their services</a>. On the other hand, figuring out the configuration to implement the automation steps I came up with is far from trivial&#8230;</p>
<p>Setting up Home Assistant is pretty simple. Create a new directory, add a new virtualenv environment, and install home assistant (I&#8217;ve added some bonus modules that the logs recommended):</p>
<pre class="lang:sh decode:true" title="Home Assistant and bonus modules installation">$ virtualenv env
Using base prefix '/usr'
New python executable in /tmp/env/bin/python3
Also creating executable in /tmp/env/bin/python
Installing setuptools, pip, wheel...done.
$ source env/bin/activate
(env) $ pip install homeassistant
...
(env) $ pip install python-Levenshtein
(env) $ pip install colorlog
(env) $ hass --open-ui</pre>
<p>Next step is adding the actual components (the pieces of the home automation).  I&#8217;ve implemented the Wio Link light as a <a href="https://home-assistant.io/components/switch.command_line/">Command Line Switch</a>. It has two commands for &#8220;on&#8221; and &#8220;off&#8221;, plus an extra for checking the on/off status (this latter is a very nice touch, and works well checking whether the switch took effect). In the <span class="lang:default decode:true crayon-inline">configuration.yaml</span>  file in the <span class="lang:default decode:true crayon-inline ">~/.homeassistant</span>  directory:</p>
<pre class="lang:yaml decode:true" title="Wio Link LED light as a Command Line Switch component">switch:
  platform: command_line
  switches:
    presence_light:
      name: Home Presence Light
      oncmd: "/usr/bin/curl -s -X POST https://iot.seeed.cc/v1/node/GenericDOutD0/onoff/1?access_token=&lt;token&gt;"
      offcmd: "/usr/bin/curl -s -X POST https://iot.seeed.cc/v1/node/GenericDOutD0/onoff/0?access_token=&lt;token&gt;"
      statecmd: "/usr/bin/curl -s https://iot.seeed.cc/v1/node/GenericDOutD0/onoff_status?access_token=&lt;token&gt;"
      value_template: '{{ value_json.onoff == 1 }}'

group:
  remote:
    - switch.home_presence_light</pre>
<p>Here the URLs are coming straight from Wio Link API page, and you have to add your token value and the correct channels instead of <span class="lang:default decode:true crayon-inline ">GenericDOutD0</span>  if you plugged your light into a different connector than me. I&#8217;ve also removed their <span class="lang:default decode:true crayon-inline ">-k</span>  command line parameter (allow insecure SSL connection), and added  <span class="lang:default decode:true crayon-inline ">-s</span>  (silent mode). The last section starting with &#8220;group&#8221; is not really necessary, but could group devices to be controlled together.</p>
<p>Adding the presence detection through DD-WRT is just the same as in their example configuration, obviously add your own parameters.</p>
<pre class="lang:yaml decode:true" title="DD-WRT Presence Detection component config">device_tracker:
  platform: ddwrt
  host: 192.168.x.y
  username: &lt;user&gt;
  password: &lt;password&gt;
  interval: 10</pre>
<p>I don&#8217;t like that username/password is in clear text, so better protect your Home Assistant device and this configuration file!</p>
<p>By the default configuration, after restarting Home Assistant this presence detection module will create a <span class="lang:default decode:true crayon-inline ">known_devices.yaml</span>  file in the <span class="lang:default decode:true crayon-inline ">~/.homeassistant/</span>  directory and add all new devices (see the <a href="https://home-assistant.io/components/device_tracker/">device tracker component page</a> for some more info). Here I had my smartphone, after connecting it to the home network.</p>
<pre class="lang:yaml decode:true" title="Known devices settings">xxxxxxxxxxxx:
  name: HTC One M9
  mac: xx:xx:xx:xx:xx:xx
  picture: http://www.gravatar.com/avatar/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  track: yes
  hide_if_away: no</pre>
<p>That file then can be edited, for example  adding device name, disabling tracking for some discovered devices (eg. the small server running the Home Assistant server itself), and adding an image. I&#8217;ve added an image using a <a href="https://en.gravatar.com/">Gravatar</a> link, where the xxxx section is just the md5 hash of your email, get it by.</p>
<pre class="lang:sh decode:true">echo -n "my@email.com" | md5sum -</pre>
<p>Alternatively, this week&#8217;s update added local file support too, as it was <a href="https://home-assistant.io/blog/2016/04/07/static-website/">discussed in the Home Assistant blog</a>, so files in the <span class="lang:default decode:true crayon-inline">~/.homeassistant/www/</span>  can be linked through the <span class="lang:default decode:true crayon-inline ">http://127.0.0.1/local/</span>  path, so no online link is necessary (but I think Gravatar is a good unified approach).</p>
<p>After all this, the control interface will look something like this (the Sun is added as I had my home&#8217;s longitude/latitude information in the configuration). My icon will show Home/Away status, and clicking the switch on the presence light will trigger the light on the Wio Link.</p>
<p><figure id="attachment_2249" aria-describedby="caption-attachment-2249" style="width: 604px" class="wp-caption aligncenter"><a href="https://gergely.imreh.net/blog/wp-content/uploads/2016/04/HomeAssistant_Interface.png" rel="attachment wp-att-2249"><img loading="lazy" decoding="async" class="size-large wp-image-2249" src="https://gergely.imreh.net/blog/wp-content/uploads/2016/04/HomeAssistant_Interface-1024x640.png" alt="Home Assistant control interface: sun, device tracker, and switch" width="604" height="378" srcset="https://gergely.imreh.net/blog/wp-content/uploads/2016/04/HomeAssistant_Interface-1024x640.png 1024w, https://gergely.imreh.net/blog/wp-content/uploads/2016/04/HomeAssistant_Interface-500x313.png 500w, https://gergely.imreh.net/blog/wp-content/uploads/2016/04/HomeAssistant_Interface-768x480.png 768w, https://gergely.imreh.net/blog/wp-content/uploads/2016/04/HomeAssistant_Interface.png 1280w" sizes="auto, (max-width: 604px) 100vw, 604px" /></a><figcaption id="caption-attachment-2249" class="wp-caption-text">Home Assistant control interface: sun, device tracker, and switch</figcaption></figure></p>
<p>The final step is the automation. This was the hardest step, as the <a href="https://home-assistant.io/getting-started/automation/">Home Assistant automation documentation</a> and their cookbook is pretty shallow, and often feel confusing. In the end, one working result is this pair of rules, which turn the light on when status change to <span class="lang:default decode:true crayon-inline ">home</span> , and turn it off when changes to <span class="lang:default decode:true crayon-inline ">not_home</span>  for that particular device.</p>
<pre class="lang:yaml decode:true" title="Home/Away signalling through automation">automation 1:
  trigger:
    platform: state
    entity_id: device_tracker.xxxxxxxxxxxx
    to: 'home'
  action:
    service: homeassistant.turn_on
    entity_id: group.remote

automation 2:
  trigger:
    platform: state
    entity_id: device_tracker.xxxxxxxxxxxx
    to: 'not_home'
  action:
    service: homeassistant.turn_off
    entity_id: group.remote
</pre>
<p>I&#8217;m sure it can be done differently, but I&#8217;m also just glad it works, as it took quite a few hours of checking documentation, trying things, and reading the <a href="https://github.com/balloob/home-assistant">Home Assistant source code</a> to come up with a working solution.</p>
<p>It functions pretty well, though presence (arriving) is detected quicker than absence (going away), I guess that&#8217;s part of detection method and certain timeouts within DD-WRT.</p>
<h2>Lessons</h2>
<p>I quite like how it all turned out, and I&#8217;ve learned a lot along the way, in the about 5-6 hours it took to pull everything together for the first time.</p>
<p>There will always be <strong>bugs</strong>. When trying to read the Wio Link LED&#8217;s status, first I was trying to implement it as a <a href="https://home-assistant.io/components/binary_sensor.rest/">RESTful Binary Sensor</a>. Took a while to find that that component had a breaking bug. I&#8217;ve made a patch, but haven&#8217;t sent it upstream yet, because Home Assistant makes me fill out so much information before a pull request can be even considered. To make it worthwhile, I&#8217;ll review things and send the fix later.</p>
<p>Not all the Wio Link <strong>API design</strong> is great. In particular, turning the light on/off are empty POST request to two different API endpoints! That&#8217;s not really REST at all. I think the way it should have been is using the same API endpoint (one single URL), and the setting sent over the POST data. Because of peculiarity, I couldn&#8217;t implement the Wio Link control over the <a href="https://home-assistant.io/components/switch.rest/">RESTful Switch</a> component, which requires a single endpoint.</p>
<p>Since the Wio Link can be placed anywhere where there&#8217;s internet connection, this home automation system can incorporate <strong>data from anywhere</strong>, sending or receiving. Can have an <a href="http://www.seeedstudio.com/wiki/Grove_-_LCD_RGB_Backlight">LCD screen</a> miles away that displays metrics from your home. Can incorporate external sensors, actuators, the whole shebang. This makes more of a &#8220;local area&#8221; or even &#8220;wide area&#8221; automation network, not just &#8220;home&#8221;. Let your imagination run amok!</p>
<p>The Home Assistant <strong>documentation</strong> is really lacking for me, and I say that while every component has code samples and there are a lot of cookbook samples around. The problem is that there&#8217;s very little consistency, there&#8217;s no overview, and the options are not documented extensively. There&#8217;s no list of &#8220;these are all the options and possible values&#8221;, and there are no &#8220;these are all the ways you can do this thing&#8221;. In the end, one needs a lot of trial and error and monumental amount of head scratching! (Use the Source, Luke!) All this basically means that Home Assistant is the &#8220;<em>worst documented project that I&#8217;m the most excited about</em>&#8220;. :) Fortunately the <a href="https://github.com/balloob/home-assistant.io">Home Assistant website&#8217;s source</a> is also on Github and can submit updates if I figure out how to explain things better.</p>
<p>Creating automation through triggers, conditions, and actions is probably pretty straightforward at first. I guess it works very well for simple systems, though I wonder how it could be made to scale better. In this <strong>configuration based system</strong>, even just a couple of automation scripts can balloon to pages and pages of code, and possible very little operator understanding how rules possible cross-interact with each other. I don&#8217;t know what model would be better (some kind of state machine definition maybe?), but it would worth thinking about it for the long term of home automation.</p>
<p>There are more <strong>components</strong> defined than I could reasonably ever try in my life, just check the component&#8217;s page!</p>
<p><figure id="attachment_2250" aria-describedby="caption-attachment-2250" style="width: 604px" class="wp-caption aligncenter"><a href="https://gergely.imreh.net/blog/wp-content/uploads/2016/04/HomeAssistant_Choices.png" rel="attachment wp-att-2250"><img loading="lazy" decoding="async" class="size-large wp-image-2250" src="https://gergely.imreh.net/blog/wp-content/uploads/2016/04/HomeAssistant_Choices-1024x640.png" alt="Home Assistant components galore" width="604" height="378" srcset="https://gergely.imreh.net/blog/wp-content/uploads/2016/04/HomeAssistant_Choices-1024x640.png 1024w, https://gergely.imreh.net/blog/wp-content/uploads/2016/04/HomeAssistant_Choices-500x313.png 500w, https://gergely.imreh.net/blog/wp-content/uploads/2016/04/HomeAssistant_Choices-768x480.png 768w, https://gergely.imreh.net/blog/wp-content/uploads/2016/04/HomeAssistant_Choices.png 1280w" sizes="auto, (max-width: 604px) 100vw, 604px" /></a><figcaption id="caption-attachment-2250" class="wp-caption-text"><a href="https://home-assistant.io/components/">Home Assistant components</a> galore</figcaption></figure></p>
<p>This abundance also means that the number of possible combinations are astronomical. I would wager, though, that the value of those combinations follow a power-low: most of the combinations are not interesting at all, while a relatively small number of combinations are the most useful in general! I guess the <a href="https://home-assistant.io/cookbook/">Cookbook</a> would be a good place to highlight some more &#8220;common use cases&#8221;, not just covering the bases and filling in for the lack of documentation. There are some obviously more useful components, <a href="https://ifttt.com/">IFTTT</a> component on its own can add a ton of functionality, or the RESTful components.</p>
<h2>Future</h2>
<p>I hope, that <strong>more device manufacturers</strong> will create components and generously add it to this lineup. I can&#8217;t see any downside and there&#8217;s just so much upside working with an open source system! Any system integrator that figures out Home Assistant will also have a big competitive advantage in some niches for sure.</p>
<p>I hope, that the <strong>documentation</strong> can be improved in the future and things will be easier to figure out (e.g. how would I update this project above to light up the LED if any one of the tracked devices is present and turn the LED off when all of them are absent?).</p>
<p>The huge number of possible <strong>component combinations</strong> to mix-and-match is also pretty paralyzing too (see the classic <a href="https://www.ted.com/talks/barry_schwartz_on_the_paradox_of_choice?language=en">Paradox of Choice</a>), I have no good &#8220;production-level&#8221; project in mind yet, even though I&#8217;m super excited about many components I&#8217;ve found so far! This particular project worked, because it&#8217;s already something I was thinking about, and could possibly replace <a href="https://gergely.imreh.net/blog/2013/07/electronic-check-in-at-the-taipei-hackerspace/">an existing system in the Taipei Hackerspace</a>!</p>
<p>Have you built something interesting? Would love to hear about it! :)</p>
<p>The post <a href="https://gergely.imreh.net/blog/2016/04/home-automation-mix-and-match/">Home Automation Mix-and-Match</a> appeared first on <a href="https://gergely.imreh.net/blog">ClickedyClick</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://gergely.imreh.net/blog/2016/04/home-automation-mix-and-match/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>

<!--
Performance optimized by W3 Total Cache. Learn more: https://www.boldgrid.com/w3-total-cache/?utm_source=w3tc&utm_medium=footer_comment&utm_campaign=free_plugin

Object Caching 9/172 objects using APC
Page Caching using Disk: Enhanced 
Lazy Loading (feed)

Served from: gergely.imreh.net @ 2026-04-26 02:29:54 by W3 Total Cache
-->