<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[IoT-Fish Blog]]></title><description><![CDATA[IoT-Fish Blog]]></description><link>https://stankevicius.dev</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1656954104228/7XMberSXv.png</url><title>IoT-Fish Blog</title><link>https://stankevicius.dev</link></image><generator>RSS for Node</generator><lastBuildDate>Tue, 13 Oct 2026 12:20:31 GMT</lastBuildDate><atom:link href="https://stankevicius.dev/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Secure MQTT with ESP32: Hot-Seat Project]]></title><description><![CDATA[The Hot-Seat project was inspired by a simple, real-world problem.On sunny days, the window behind my desk shines directly onto my workspace, turning it into an unexpectedly warm spot. I wanted to measure how hot it actually gets during the day, and ...]]></description><link>https://stankevicius.dev/secure-mqtt-with-esp32-hot-seat-project</link><guid isPermaLink="true">https://stankevicius.dev/secure-mqtt-with-esp32-hot-seat-project</guid><category><![CDATA[ESP32]]></category><category><![CDATA[embedded]]></category><category><![CDATA[mqtt]]></category><category><![CDATA[C]]></category><dc:creator><![CDATA[Antanas Stankevičius]]></dc:creator><pubDate>Sun, 25 Jan 2026 12:20:37 GMT</pubDate><content:encoded><![CDATA[<p>The <strong>Hot-Seat</strong> project was inspired by a simple, real-world problem.<br />On sunny days, the window behind my desk shines directly onto my workspace, turning it into an unexpectedly warm spot. I wanted to measure how hot it actually gets during the day, and at the same time experiment with secure MQTT communication on ESP32.</p>
<p>That’s how the Hot-Seat project was born.</p>
<h3 id="heading-technologies-used">Technologies Used</h3>
<ul>
<li><p><strong>Platform:</strong> ESP32-WROOM SoC</p>
</li>
<li><p><strong>SDK:</strong> Espressif ESP-IDF</p>
</li>
<li><p><strong>MQTT Broker:</strong> HiveMQ (MQTTS)</p>
</li>
</ul>
<h3 id="heading-project-overview">Project overview</h3>
<p>The goal of this project was to implement a small IoT gadget that:</p>
<ul>
<li><p>connects to a Wi-Fi network</p>
</li>
<li><p>establishes a secure MQTT (TLS) connection</p>
</li>
<li><p>periodically publishes temperature data to a cloud MQTT broker</p>
</li>
</ul>
<p>The focus was on clean setup, secure communication, and simplicity, rather than complex hardware integration.</p>
<h3 id="heading-device-behavior">Device Behavior</h3>
<p>The device workflow is straightforward:</p>
<ul>
<li><p>Connect to the configured Wi-Fi network</p>
</li>
<li><p>Establish a secure MQTT connection using TLS</p>
</li>
<li><p>Publish temperature readings at a fixed interval</p>
</li>
</ul>
<p>At the current stage, temperature values are simulated. The project is structured so that a real temperature and humidity sensor can be added later without major refactoring.</p>
<h3 id="heading-source-code">Source Code:</h3>
<p>If this project sounds interesting, the full source code and implementation details are available on GitHub:</p>
<p>👉 <a target="_blank" href="https://github.com/antanasstankevicius/hot-seat"><strong>GitHub repository link</strong></a></p>
]]></content:encoded></item><item><title><![CDATA[Bluetooth Relay & Silicon Labs]]></title><description><![CDATA[This project was inspired by a real-world business case that required a wireless-controlled relay used to control a vehicle’s fuel pump or starting mechanism in order to prevent vehicle theft.
In this scenario, the relay is installed inside the vehic...]]></description><link>https://stankevicius.dev/bluetooth-relay-and-silicon-labs</link><guid isPermaLink="true">https://stankevicius.dev/bluetooth-relay-and-silicon-labs</guid><category><![CDATA[silicon-labs]]></category><category><![CDATA[bluetooth]]></category><category><![CDATA[Bluetooth Low Energy]]></category><category><![CDATA[Programming Blogs]]></category><dc:creator><![CDATA[Antanas Stankevičius]]></dc:creator><pubDate>Fri, 23 Jan 2026 09:12:11 GMT</pubDate><content:encoded><![CDATA[<p>This project was inspired by a real-world business case that required a wireless-controlled relay used to control a vehicle’s fuel pump or starting mechanism in order to prevent vehicle theft.</p>
<p>In this scenario, the relay is installed inside the vehicle and acts as a Bluetooth Low Energy (BLE) slave. A separate specialized vehicle tracking device (GNSS tracker) acts as the BLE master and controls the relay wirelessly. To explore this concept in practice, I created a small Proof of Concept using the Silicon Labs xG24 Explorer Kit.</p>
<h3 id="heading-technologies-used">Technologies Used</h3>
<ul>
<li><p><strong>IDE:</strong> Simplicity Studio</p>
</li>
<li><p><strong>Platform:</strong> Silicon Labs xG24 Explorer Kit</p>
</li>
<li><p><strong>SDK:</strong> Simplicity SDK</p>
</li>
</ul>
<h3 id="heading-project-overview">Project Overview</h3>
<p>The goal of this PoC was to implement a simple BLE-controlled relay with predictable behavior on connection and disconnection events. The relay itself is represented by an LED, allowing the focus to remain on software architecture and logic rather than hardware complexity.</p>
<p>The relay behavior is straightforward:</p>
<ul>
<li><p>When BLE is connected, the relay is kept OFF by default, and waits for BLE master signal</p>
</li>
<li><p>When BLE is disconnected, a timer starts</p>
</li>
<li><p>If the device remains disconnected for a defined timeout, the relay turns ON</p>
</li>
<li><p>If the connection is restored before the timeout expires, the relay remains OFF</p>
</li>
</ul>
<h3 id="heading-development-experience">Development Experience</h3>
<p>My overall experience with Simplicity Studio was positive. The IDE allows for quick board bring-up and project configuration, which makes it easy to prototype ideas and test assumptions.</p>
<p>For this PoC, I started with the Blinky example and gradually adapted it to the project’s needs. I removed unused GPIO logic, explored timer usage, and modified BLE characteristics. The required documentation was easy to find directly within Simplicity Studio, which helped maintain development momentum.</p>
<p>I also found the Silicon Labs VS Code plugin particularly useful. It provides a clean and efficient workflow for common tasks such as building and flashing firmware, without constantly switching contexts.</p>
<h3 id="heading-unit-testing">Unit Testing</h3>
<p>On top of the firmware implementation, I integrated the CppUTest framework to write unit tests for the relay logic. The core logic is intentionally decoupled from hardware and BLE stack details, making it possible to test it in isolation on a host machine.</p>
<p>This setup helps validate behavior such as disconnect timeouts and reconnection handling without relying on physical hardware during every change.</p>
<h3 id="heading-source-code">Source Code</h3>
<p>If this project sounds interesting, the full source code and implementation details are available on GitHub:</p>
<p>👉 <a target="_blank" href="https://github.com/antanasstankevicius/ble-relay">GitHub repository link</a></p>
]]></content:encoded></item><item><title><![CDATA[Open-Closed Principle (OCP)]]></title><description><![CDATA[The Open-Closed Principle (OCP) can be be described this way:

A software component should be open for extension but closed for modification.

In other words, when requirements change, the module should change as minimum as possible. Ideally, no chan...]]></description><link>https://stankevicius.dev/open-closed-principle-ocp</link><guid isPermaLink="true">https://stankevicius.dev/open-closed-principle-ocp</guid><category><![CDATA[SOLID principles]]></category><category><![CDATA[solid]]></category><category><![CDATA[fishing]]></category><dc:creator><![CDATA[Antanas Stankevičius]]></dc:creator><pubDate>Mon, 04 Jul 2022 19:50:56 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1656964100462/VgIphGyWb.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The <strong>Open-Closed Principle (OCP)</strong> can be be described this way:</p>
<blockquote>
<p>A software component should be open for extension but closed for modification.</p>
</blockquote>
<p>In other words, when requirements change, the module should change as minimum as possible. Ideally, no changes. Developer should be able to extend a module by adding new code.</p>
<p>Lets take a look how would this look like from fisherman perspective. Imagine that we have seat box, which we want to expand with accessories like feeder arm and butt rest.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1656960668746/gjztaT0Rq.png" alt="OCP SeatBox.png" class="image--center mx-auto" /></p>
<p>From developer perspective this could be implemented by listing all accessories under <code>SeatBoxAccessory</code> enumeration class. Later <code>SeatBox</code> class could be initialised depending on the accessory we want.</p>
<pre><code><span class="hljs-keyword">enum</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SeatBoxAccessory</span> {</span>
    feederArm,
    buttRest
};

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">SeatBox</span> {</span>
<span class="hljs-keyword">private</span>:
    SeatBoxAccessory accessory;
<span class="hljs-keyword">public</span>:
    SeatBox(SeatBoxAccessory accessoryType) : accessory{accessoryType} {}

    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">attachAccessory</span><span class="hljs-params">()</span> </span>{
        <span class="hljs-keyword">if</span> (accessory == SeatBoxAccessory::feederArm) {
            <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Attaching seat box accessory - Feeder Arm\n"</span>);
        } <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (accessory == SeatBoxAccessory::buttRest) {
            <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Attaching seat box accessory - Butt Rest\n"</span>);
        }
    }
};
</code></pre><p>In case later new feature request comes, such as keep net attachment, then developer will have to modify <code>SeatBox</code> class. This class has not been designed according to <strong>OCP</strong> - it is open for modification.</p>
<p>Developer will have to understand <code>SeatBox</code> class to add new accessories. This could lead to unwanted defects. Also unit test will have to be reviewed and adjusted.</p>
<p>We can refactor this example so it wouldn't violate <strong>OCP</strong>:</p>
<pre><code><span class="hljs-selector-tag">class</span> <span class="hljs-selector-tag">SeatBox</span> {
<span class="hljs-attribute">public</span>:
    virtual void <span class="hljs-built_in">attachAccessory</span>() = <span class="hljs-number">0</span>;
};

<span class="hljs-selector-tag">class</span> <span class="hljs-selector-tag">FeederArm</span> : <span class="hljs-selector-tag">public</span> <span class="hljs-selector-tag">SeatBox</span> {
<span class="hljs-attribute">public</span>:
    void <span class="hljs-built_in">attachAccessory</span>() override {
        <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Attaching seat box accessory - Feeder Arm\n"</span>);
    }
};

<span class="hljs-selector-tag">class</span> <span class="hljs-selector-tag">ButtRest</span> : <span class="hljs-selector-tag">public</span> <span class="hljs-selector-tag">SeatBox</span> {
<span class="hljs-attribute">public</span>:
    void <span class="hljs-built_in">attachAccessory</span>() override {
        <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Attaching seat box accessory - Butt Rest\n"</span>);
    }
};
</code></pre><p>The <code>SeatBox</code> class is now containing very little code, new accessories now have their own implementation of how to attach itself. If new requirement arrives to attach new accessory - developer can create new <em>Accessory</em> class that implements <code>SeatBox</code> interface without having to make any changes in <code>SeatBox</code> class or any other <em>Accessory</em> class. It is now open for extension but closed for modification.</p>
]]></content:encoded></item><item><title><![CDATA[Single Responsibility Principle (SRP)]]></title><description><![CDATA[The Single Responsibility Principle (SRP) can be described this way:

A module should have only one responsibility, and only one, reason to change.

Unfortunately, this sentence is difficult to understand without proper explanation.

What does the wo...]]></description><link>https://stankevicius.dev/single-responsibility-principle-srp</link><guid isPermaLink="true">https://stankevicius.dev/single-responsibility-principle-srp</guid><category><![CDATA[SOLID principles]]></category><category><![CDATA[solid]]></category><category><![CDATA[fishing]]></category><dc:creator><![CDATA[Antanas Stankevičius]]></dc:creator><pubDate>Tue, 28 Jun 2022 19:35:54 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1656444553400/TS8EXi6vf.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>The <strong>Single Responsibility Principle (SRP)</strong> can be described this way:</p>
<blockquote>
<p>A module should have only one responsibility, and only one, reason to change.</p>
</blockquote>
<p>Unfortunately, this sentence is difficult to understand without proper explanation.</p>
<ul>
<li>What does the word "module" mean?</li>
</ul>
<p>The simple definition is a source file. We group together the functions that need to change for the same reason, and separate the things that change for other reasons.</p>
<ul>
<li>What does "reason to change" mean?</li>
</ul>
<p>Software systems are changed to satisfy actors, usually they are called users and stakeholders. Actors are the "reason to change".</p>
<ul>
<li>Why should you follow SRP?</li>
</ul>
<p>If a module has multiple responsibilities, there is a likelihood that it is used in a lot of places. When one responsibility is changed, not only do we run a higher risk of introducing defects into other responsibilities in the same class, but there is a greater number of other actors that might be impacted.</p>
<p>By following the single responsibility principle, if we need to change a particular responsibility, that change would be located in a single module.</p>
<p>Let's take a look at an example of the SRP. It is written in C++, although you will get the idea even if you do not use that particular programming language. We have a fishing rod service which is responsible for casting and retrieving. There is requirement to prepare fishing rod before fishing, this includes assembling the rod, tying fishing rig and hooking bait.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1656354604942/iEneHqsEd.png" alt="paveikslas.png" class="image--center mx-auto" /></p>
<pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">FishingRod</span> {</span>
<span class="hljs-keyword">public</span>:
    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">assembleRod</span><span class="hljs-params">(<span class="hljs-keyword">void</span>)</span> </span>{
        <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Assembling TWO PEACE rod by JOINING TWO PIECES\n"</span>);
        <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Placing reel in reel seat and fasten it\n"</span>);
        <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Passing line through blank rings\n"</span>);
    }

    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">joinRig</span><span class="hljs-params">(<span class="hljs-keyword">void</span>)</span> </span>{
        <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Tying FREE RUNNING rig\n"</span>);
    }

    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">prepareHook</span><span class="hljs-params">(<span class="hljs-keyword">void</span>)</span> </span>{
        <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Pulling WORM down onto the hook\n"</span>);
    }

    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">cast</span><span class="hljs-params">(<span class="hljs-keyword">void</span>)</span> </span>{
        <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Casting\n"</span>);
    }

    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">retrieve</span><span class="hljs-params">(<span class="hljs-keyword">void</span>)</span> </span>{
        <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Retrieving\n"</span>);
    }
};
</code></pre><p>This class violates the SRP because functions are responsible to different actors:</p>
<ul>
<li><p>The <code>assembleRod()</code> and <code>joinRig()</code> functions are specified by Fisherman, depending on which blanks and reels are brought to the session.</p>
</li>
<li><p>The <code>prepareHook()</code> functions is specified and used by Fish, it depends on mood what they want to eat at that time.</p>
</li>
<li><p>The <code>cast()</code> and <code>retrieve()</code> functions are specified by Rod'n'Reel combination.</p>
</li>
</ul>
<p>As you can see in this example, this class has more than one responsibility and more than one reason to change. By putting the source code for all functions into single <code>FishingRod</code> class, developer have coupled all of the actors. If we wanted to change rig, provide new bait for the Fish, both would require changes to the same module.</p>
<p>To solve this issue developer needs to move the functions to different classes.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1656439906055/gfOtXGIx3.png" alt="paveikslas.png" class="image--center mx-auto" /></p>
<pre><code><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">AssembleRod</span> {</span>
<span class="hljs-keyword">public</span>:
    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">blank</span><span class="hljs-params">(<span class="hljs-keyword">void</span>)</span> </span>{
        <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Assembling TWO PEACE rod by JOINING TWO PIECES\n"</span>);
        <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Placing reel in reel seat and fasten it\n"</span>);
        <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Passing line through 10 blank RINGS\n"</span>);
    }

    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">rig</span><span class="hljs-params">(<span class="hljs-keyword">void</span>)</span> </span>{
        <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Tying FREE RUNNING rig\n"</span>);
    }
};

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PrepareHook</span> {</span>
<span class="hljs-keyword">public</span>:
    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">worm</span><span class="hljs-params">(<span class="hljs-keyword">void</span>)</span> </span>{
        <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Pulling WORM down onto the hook\n"</span>);
    }
};

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">RodAction</span> {</span>
<span class="hljs-keyword">public</span>:
    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">cast</span><span class="hljs-params">(<span class="hljs-keyword">void</span>)</span> </span>{
        <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Casting\n"</span>);
    }

    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">retrieve</span><span class="hljs-params">(<span class="hljs-keyword">void</span>)</span> </span>{
        <span class="hljs-built_in">printf</span>(<span class="hljs-string">"Retrieving\n"</span>);
    }
};

<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">FishingRodFacade</span>:</span> <span class="hljs-keyword">public</span> AssembleRod, <span class="hljs-keyword">public</span> PrepareHook, <span class="hljs-keyword">public</span> RodAction {
<span class="hljs-keyword">public</span>:
    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">assembleRod</span><span class="hljs-params">(<span class="hljs-keyword">void</span>)</span> </span>{
        blank();
    }

    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">joinRig</span><span class="hljs-params">(<span class="hljs-keyword">void</span>)</span> </span>{
        rig();
    }

    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">prepareHook</span><span class="hljs-params">(<span class="hljs-keyword">void</span>)</span> </span>{
        worm();
    }

    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">castRod</span><span class="hljs-params">(<span class="hljs-keyword">void</span>)</span> </span>{
        cast();
    }

    <span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">retrieveRod</span><span class="hljs-params">(<span class="hljs-keyword">void</span>)</span> </span>{
       retrieve();
    }
};
</code></pre><p>To solve this issue developer can use the <em>Facade</em> pattern. The <code>FishingRodFacade</code> contains very little code. It is responsible for providing simple interface to the client.</p>
<p>All classes are now only responsible for a single thing and therefore has only one reason to change. This implementation no longer violates the <strong>Single <em>Rod</em> Principle</strong>.</p>
]]></content:encoded></item></channel></rss>