<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: freelancing</title>
    <description>The latest articles on DEV Community by freelancing (@freelancing_2b362430a47f8).</description>
    <link>https://dev.to/freelancing_2b362430a47f8</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4163870%2F3818068d-1832-4253-92da-7d86476cd09a.png</url>
      <title>DEV Community: freelancing</title>
      <link>https://dev.to/freelancing_2b362430a47f8</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/freelancing_2b362430a47f8"/>
    <language>en</language>
    <item>
      <title>Build an Accessible Daily Habit Tracker with HTML, CSS and JavaScript</title>
      <dc:creator>freelancing</dc:creator>
      <pubDate>Thu, 22 Oct 2026 15:30:40 +0000</pubDate>
      <link>https://dev.to/freelancing_2b362430a47f8/build-an-accessible-daily-habit-tracker-with-html-css-and-javascript-2dmk</link>
      <guid>https://dev.to/freelancing_2b362430a47f8/build-an-accessible-daily-habit-tracker-with-html-css-and-javascript-2dmk</guid>
      <description>&lt;p&gt;A daily habit tracker is a simple project for practising front-end development. It can also teach important lessons about accessibility, semantic HTML and clear user feedback.&lt;/p&gt;

&lt;p&gt;In this tutorial, we'll build a checklist that tracks completion of a few daily habits. The example uses generic habits and can be adapted for personal routines, study goals or reminders.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Create the HTML
&lt;/h2&gt;

&lt;p&gt;Save the following as &lt;code&gt;index.html&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Daily Habit Tracker&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;link&lt;/span&gt; &lt;span class="na"&gt;rel=&lt;/span&gt;&lt;span class="s"&gt;"stylesheet"&lt;/span&gt; &lt;span class="na"&gt;href=&lt;/span&gt;&lt;span class="s"&gt;"style.css"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;main&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"container"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Daily Habit Tracker&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;Mark each habit when you complete it.&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;ul&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"habits"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;label&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"checkbox"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
          Morning routine
        &lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;label&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"checkbox"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
          Evening routine
        &lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;li&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;label&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"checkbox"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
          Prepare for tomorrow
        &lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/li&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/ul&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"progress"&lt;/span&gt; &lt;span class="na"&gt;aria-live=&lt;/span&gt;&lt;span class="s"&gt;"polite"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      0 of 3 habits completed
    &lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/main&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"script.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2: Make it responsive
&lt;/h2&gt;

&lt;p&gt;Create &lt;code&gt;style.css&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight css"&gt;&lt;code&gt;&lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;box-sizing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;border-box&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;24px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;system-ui&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;sans-serif&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;line-height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1.6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#20252b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#f4f6f8&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;560px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;40px&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;24px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="no"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;12px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;ul&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;list-style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;none&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;li&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;12px&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;12px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1px&lt;/span&gt; &lt;span class="nb"&gt;solid&lt;/span&gt; &lt;span class="m"&gt;#ddd&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;border-radius&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;8px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;label&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;display&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;flex&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;align-items&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="py"&gt;gap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;12px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;cursor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;pointer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nt"&gt;input&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="nt"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;"checkbox"&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;height&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;@media&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max-width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;480px&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nt"&gt;body&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;12px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nc"&gt;.container&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;16px&lt;/span&gt; &lt;span class="nb"&gt;auto&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nl"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;18px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: Add progress tracking
&lt;/h2&gt;

&lt;p&gt;Create &lt;code&gt;script.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;habitList&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#habits&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;progress&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#progress&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;updateProgress&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;checkboxes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;habitList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;input[type="checkbox"]&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;completed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[...&lt;/span&gt;&lt;span class="nx"&gt;checkboxes&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nx"&gt;checkbox&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;checkbox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;checked&lt;/span&gt;
  &lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;progress&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;completed&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; of &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;checkboxes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; habits completed`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;habitList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;change&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;updateProgress&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nf"&gt;updateProgress&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why accessibility matters
&lt;/h2&gt;

&lt;p&gt;A useful interface should work for people who navigate using a keyboard or assistive technology.&lt;/p&gt;

&lt;p&gt;This example uses semantic HTML, connects each checkbox to a label and provides a status message with &lt;code&gt;aria-live="polite"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The browser can announce progress changes to assistive technology without forcing the user to search for the updated text.&lt;/p&gt;

&lt;p&gt;You should also test keyboard navigation, visible focus indicators, contrast and behaviour at different screen sizes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ideas for extending the project
&lt;/h2&gt;

&lt;p&gt;Once the basic version works, consider adding custom habits, a date selector or a weekly progress summary.&lt;/p&gt;

&lt;p&gt;You could also save the checklist between sessions. If you use local storage, remember that the information stays in the browser and is not automatically synchronised across devices.&lt;/p&gt;

&lt;p&gt;Avoid collecting sensitive personal information unless your application has a clear need and appropriate privacy protections.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This small project combines HTML structure, responsive CSS and JavaScript event handling. More importantly, it shows how accessibility can be considered from the beginning rather than added as an afterthought.&lt;/p&gt;

&lt;p&gt;Building a simple interface well is a valuable step towards developing more complex web applications.&lt;/p&gt;

</description>
      <category>css</category>
      <category>html</category>
      <category>javascript</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Build a Monthly Loan Repayment Calculator with JavaScript</title>
      <dc:creator>freelancing</dc:creator>
      <pubDate>Thu, 22 Oct 2026 15:30:00 +0000</pubDate>
      <link>https://dev.to/freelancing_2b362430a47f8/build-a-monthly-loan-repayment-calculator-with-javascript-2fl3</link>
      <guid>https://dev.to/freelancing_2b362430a47f8/build-a-monthly-loan-repayment-calculator-with-javascript-2fl3</guid>
      <description>&lt;p&gt;A loan repayment calculator is a practical beginner project for learning JavaScript functions, mathematical formulas, input validation and DOM manipulation.&lt;/p&gt;

&lt;p&gt;In this tutorial, we will create a calculator that estimates the monthly repayment for a standard fixed-rate amortising loan.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding the formula
&lt;/h2&gt;

&lt;p&gt;The monthly repayment is calculated using:&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
M=P\frac{r(1+r)^n}{(1+r)^n-1}&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;Where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;P&lt;/code&gt; is the principal.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;r&lt;/code&gt; is the monthly interest rate expressed as a decimal.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;n&lt;/code&gt; is the total number of monthly payments.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;M&lt;/code&gt; is the estimated monthly repayment.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The annual percentage rate is divided by 100 and then by 12 to obtain the monthly rate.&lt;/p&gt;

&lt;p&gt;When the interest rate is zero, the formula needs a separate case: divide the principal by the number of payments.&lt;/p&gt;
&lt;h2&gt;
  
  
  Step 1: Create the HTML
&lt;/h2&gt;

&lt;p&gt;Save this as &lt;code&gt;index.html&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Loan Calculator&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Loan Repayment Calculator&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"loan-form"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"principal"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Loan amount&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"principal"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"number"&lt;/span&gt; &lt;span class="na"&gt;min=&lt;/span&gt;&lt;span class="s"&gt;"0.01"&lt;/span&gt;
           &lt;span class="na"&gt;step=&lt;/span&gt;&lt;span class="s"&gt;"0.01"&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"rate"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Annual interest rate (%)&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"rate"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"number"&lt;/span&gt; &lt;span class="na"&gt;min=&lt;/span&gt;&lt;span class="s"&gt;"0"&lt;/span&gt;
           &lt;span class="na"&gt;step=&lt;/span&gt;&lt;span class="s"&gt;"0.01"&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;label&lt;/span&gt; &lt;span class="na"&gt;for=&lt;/span&gt;&lt;span class="s"&gt;"years"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Loan term (years)&lt;span class="nt"&gt;&amp;lt;/label&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"years"&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"number"&lt;/span&gt; &lt;span class="na"&gt;min=&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt;
           &lt;span class="na"&gt;max=&lt;/span&gt;&lt;span class="s"&gt;"50"&lt;/span&gt; &lt;span class="na"&gt;step=&lt;/span&gt;&lt;span class="s"&gt;"1"&lt;/span&gt; &lt;span class="na"&gt;required&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;button&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"submit"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Calculate&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"result"&lt;/span&gt; &lt;span class="na"&gt;aria-live=&lt;/span&gt;&lt;span class="s"&gt;"polite"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"script.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2: Implement the calculation
&lt;/h2&gt;

&lt;p&gt;Save this as &lt;code&gt;script.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#loan-form&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#result&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;form&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;submit&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;preventDefault&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;principal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#principal&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;annualRate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#rate&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;years&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#years&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isFinite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;principal&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
    &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isFinite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;annualRate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
    &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isFinite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;years&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
    &lt;span class="nx"&gt;principal&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
    &lt;span class="nx"&gt;annualRate&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
    &lt;span class="nx"&gt;years&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
    &lt;span class="nx"&gt;years&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;50&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
    &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isInteger&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;years&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Enter valid loan details.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;monthlyRate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;annualRate&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;payments&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;years&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;monthlyPayment&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;monthlyRate&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;monthlyPayment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;principal&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nx"&gt;payments&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;factor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;pow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;monthlyRate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="nx"&gt;payments&lt;/span&gt;
    &lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="nx"&gt;monthlyPayment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
      &lt;span class="nx"&gt;principal&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;monthlyRate&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;factor&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;factor&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="s2"&gt;`Estimated monthly repayment: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;monthlyPayment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: Test the calculator
&lt;/h2&gt;

&lt;p&gt;Try different loan amounts, interest rates and repayment periods.&lt;/p&gt;

&lt;p&gt;Useful test cases include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A positive interest rate.&lt;/li&gt;
&lt;li&gt;A zero interest rate.&lt;/li&gt;
&lt;li&gt;A very small principal.&lt;/li&gt;
&lt;li&gt;Invalid or missing inputs.&lt;/li&gt;
&lt;li&gt;The maximum supported loan term.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, with a principal of 100,000, an annual rate of 6% and a term of 20 years, the estimated monthly repayment is approximately 716.43 in the same currency units as the principal.&lt;/p&gt;

&lt;p&gt;The result is an estimate, not a quote from a lender.&lt;/p&gt;

&lt;h2&gt;
  
  
  Possible improvements
&lt;/h2&gt;

&lt;p&gt;You could extend the project by adding:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Currency formatting.&lt;/li&gt;
&lt;li&gt;Total repayment and total interest.&lt;/li&gt;
&lt;li&gt;An amortisation table.&lt;/li&gt;
&lt;li&gt;Input fields for additional fees.&lt;/li&gt;
&lt;li&gt;Automated tests for the calculation function.&lt;/li&gt;
&lt;li&gt;A responsive CSS layout.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Separating the mathematical calculation from the user interface would also make the code easier to test and maintain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This project demonstrates how a mathematical formula can become an interactive web application. It is also a useful reminder that software outputs depend on assumptions.&lt;/p&gt;

&lt;p&gt;The example assumes regular monthly payments and a fixed interest rate. Real loan products may include fees, variable rates and other conditions that are not represented by this calculator.&lt;/p&gt;

&lt;p&gt;Use it as a programming exercise rather than as personalised financial guidance.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Build a Simple Water Quality Monitoring Dashboard with JavaScript</title>
      <dc:creator>freelancing</dc:creator>
      <pubDate>Thu, 22 Oct 2026 15:29:10 +0000</pubDate>
      <link>https://dev.to/freelancing_2b362430a47f8/build-a-simple-water-quality-monitoring-dashboard-with-javascript-4ojn</link>
      <guid>https://dev.to/freelancing_2b362430a47f8/build-a-simple-water-quality-monitoring-dashboard-with-javascript-4ojn</guid>
      <description>&lt;p&gt;Water-quality monitoring is a useful example of how web development can connect data with real-world systems.&lt;/p&gt;

&lt;p&gt;A dashboard can display measurements such as pH and water temperature, show the time of the latest reading, and flag values that need review.&lt;/p&gt;

&lt;p&gt;In this tutorial, we will build a small front-end prototype using HTML and JavaScript. The example uses simulated readings, not real sensors.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are we building?
&lt;/h2&gt;

&lt;p&gt;Our dashboard will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Display a pH reading.&lt;/li&gt;
&lt;li&gt;Display a water-temperature reading.&lt;/li&gt;
&lt;li&gt;Show when the readings were updated.&lt;/li&gt;
&lt;li&gt;Reject invalid sensor values.&lt;/li&gt;
&lt;li&gt;Indicate when a reading falls outside configurable example limits.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Important:&lt;/strong&gt; The example limits below are for demonstrating software logic only. They are not a validated pool-safety standard and must not be used to determine whether water is safe to swim in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Create the HTML
&lt;/h2&gt;

&lt;p&gt;Create a file named &lt;code&gt;index.html&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;html&lt;/span&gt; &lt;span class="na"&gt;lang=&lt;/span&gt;&lt;span class="s"&gt;"en"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;head&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;charset=&lt;/span&gt;&lt;span class="s"&gt;"UTF-8"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;meta&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"viewport"&lt;/span&gt; &lt;span class="na"&gt;content=&lt;/span&gt;&lt;span class="s"&gt;"width=device-width, initial-scale=1"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;title&amp;gt;&lt;/span&gt;Water Quality Dashboard&lt;span class="nt"&gt;&amp;lt;/title&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/head&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;body&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;main&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;Water Quality Dashboard&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;section&lt;/span&gt; &lt;span class="na"&gt;aria-labelledby=&lt;/span&gt;&lt;span class="s"&gt;"ph-heading"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;h2&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"ph-heading"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;pH reading&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"ph-value"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Waiting for data...&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"ph-status"&lt;/span&gt; &lt;span class="na"&gt;aria-live=&lt;/span&gt;&lt;span class="s"&gt;"polite"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;section&lt;/span&gt; &lt;span class="na"&gt;aria-labelledby=&lt;/span&gt;&lt;span class="s"&gt;"temp-heading"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;h2&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"temp-heading"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Water temperature&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"temp-value"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Waiting for data...&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"temp-status"&lt;/span&gt; &lt;span class="na"&gt;aria-live=&lt;/span&gt;&lt;span class="s"&gt;"polite"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/section&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;p&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"updated"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/main&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;script &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"script.js"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/html&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2: Add the JavaScript
&lt;/h2&gt;

&lt;p&gt;Create &lt;code&gt;script.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;phValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#ph-value&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;phStatus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#ph-status&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tempValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#temp-value&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tempStatus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#temp-status&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;updated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;querySelector&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#updated&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Illustrative thresholds for this demo only.&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;demoLimits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;phMin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;6.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;phMax&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;8.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;temperatureMin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;temperatureMax&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;40&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;isValidNumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;number&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;Number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isFinite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;renderReading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;isValidNumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ph&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt;
    &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nf"&gt;isValidNumber&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;temperature&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;phValue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Invalid reading&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;phStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Check the incoming data.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nx"&gt;tempValue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Invalid reading&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;tempStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Check the incoming data.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nx"&gt;updated&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;phValue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ph&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;tempValue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;temperature&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toFixed&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt; °C`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;phInDemoRange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ph&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nx"&gt;demoLimits&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;phMin&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ph&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;demoLimits&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;phMax&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;temperatureInDemoRange&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;temperature&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="nx"&gt;demoLimits&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;temperatureMin&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;temperature&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="nx"&gt;demoLimits&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;temperatureMax&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;phStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;phInDemoRange&lt;/span&gt;
    &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Within demonstration range&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Outside demonstration range&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;tempStatus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;temperatureInDemoRange&lt;/span&gt;
    &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Within demonstration range&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
    &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Outside demonstration range&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="nx"&gt;updated&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;textContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;
    &lt;span class="s2"&gt;`Updated: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toLocaleString&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;simulatedReading&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;ph&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;7.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;temperature&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;26.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;timestamp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nf"&gt;renderReading&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;simulatedReading&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: Understand the data flow
&lt;/h2&gt;

&lt;p&gt;The dashboard receives an object containing measurements and a timestamp.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;renderReading()&lt;/code&gt; function first validates the values. It then updates the page using &lt;code&gt;textContent&lt;/code&gt;, which avoids interpreting the readings as HTML.&lt;/p&gt;

&lt;p&gt;Finally, it compares the readings with the example thresholds and displays a status message.&lt;/p&gt;

&lt;p&gt;In a real application, the simulated object could be replaced with data from an API or an IoT gateway.&lt;/p&gt;

&lt;h2&gt;
  
  
  What would a production system need?
&lt;/h2&gt;

&lt;p&gt;A real water-monitoring system would need more than a front-end dashboard:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Calibrated sensors and documented measurement accuracy.&lt;/li&gt;
&lt;li&gt;Secure communication between devices and the server.&lt;/li&gt;
&lt;li&gt;Validation for missing, stale or implausible readings.&lt;/li&gt;
&lt;li&gt;Appropriate thresholds based on the application and relevant guidance.&lt;/li&gt;
&lt;li&gt;Error handling and alerts for sensor failures.&lt;/li&gt;
&lt;li&gt;Regular maintenance and verification against suitable testing methods.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A dashboard should never claim that pool water is safe solely because a few sensor readings appear normal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This small project demonstrates how JavaScript can turn structured measurements into a readable dashboard. It also highlights a key principle of monitoring software: presenting data clearly is important, but validating the source and understanding the limitations are equally important.&lt;/p&gt;

&lt;p&gt;From simulated sensor projects to real IoT applications, good monitoring starts with reliable data and honest reporting of uncertainty.&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>javascript</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How Tyre Pressure Monitoring Systems Work: Direct vs. Indirect TPMS</title>
      <dc:creator>freelancing</dc:creator>
      <pubDate>Thu, 22 Oct 2026 15:27:28 +0000</pubDate>
      <link>https://dev.to/freelancing_2b362430a47f8/how-tyre-pressure-monitoring-systems-work-direct-vs-indirect-tpms-nmb</link>
      <guid>https://dev.to/freelancing_2b362430a47f8/how-tyre-pressure-monitoring-systems-work-direct-vs-indirect-tpms-nmb</guid>
      <description>&lt;p&gt;Modern vehicles use sensors and electronic systems to help drivers identify potential problems. One useful example is the Tyre Pressure Monitoring System (TPMS), which can warn drivers when tyre pressure may be too low.&lt;/p&gt;

&lt;p&gt;Understanding how TPMS works is an interesting intersection of automotive engineering, sensors and embedded software.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is TPMS?
&lt;/h2&gt;

&lt;p&gt;TPMS monitors tyre pressure or estimates pressure changes and alerts the driver when the system detects a condition that meets its warning criteria.&lt;/p&gt;

&lt;p&gt;There are two common approaches: direct and indirect monitoring.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Direct TPMS
&lt;/h2&gt;

&lt;p&gt;A direct TPMS uses pressure sensors installed in the wheels or tyre assemblies.&lt;/p&gt;

&lt;p&gt;These sensors measure tyre pressure and communicate information to the vehicle's monitoring system. Depending on the design, the system may also report temperature or other sensor information.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Advantages:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Measures pressure directly.&lt;/li&gt;
&lt;li&gt;Can identify pressure changes in individual tyres.&lt;/li&gt;
&lt;li&gt;May provide tyre-specific readings on the dashboard.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Limitations:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sensors require power.&lt;/li&gt;
&lt;li&gt;Sensor batteries may eventually need replacement.&lt;/li&gt;
&lt;li&gt;Sensor servicing and replacement can require specialised equipment.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. Indirect TPMS
&lt;/h2&gt;

&lt;p&gt;An indirect TPMS generally uses data from the vehicle's wheel-speed sensors, which are also used by systems such as ABS.&lt;/p&gt;

&lt;p&gt;When a tyre loses pressure, its rolling characteristics can change. The monitoring software analyses wheel behaviour and looks for patterns consistent with pressure loss.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Advantages:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Can use existing vehicle sensors.&lt;/li&gt;
&lt;li&gt;Does not require a pressure sensor inside every tyre.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Limitations:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Estimates pressure loss rather than measuring pressure directly.&lt;/li&gt;
&lt;li&gt;May require calibration or a reset procedure.&lt;/li&gt;
&lt;li&gt;Performance depends on the system design and operating conditions.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why the warning light matters
&lt;/h2&gt;

&lt;p&gt;A TPMS warning can indicate that one or more tyres need attention, but the exact meaning depends on the vehicle.&lt;/p&gt;

&lt;p&gt;If the warning appears, check the owner's manual and inspect tyre pressures when safe to do so. Use the manufacturer's recommended pressure rather than the maximum pressure printed on the tyre sidewall.&lt;/p&gt;

&lt;p&gt;A TPMS warning does not replace visual inspections. Tyre damage, embedded objects and other problems may require attention even when no warning appears.&lt;/p&gt;

&lt;h2&gt;
  
  
  A useful lesson for developers
&lt;/h2&gt;

&lt;p&gt;TPMS is an example of a larger engineering principle: sensor data becomes useful when software interprets it and communicates the result clearly.&lt;/p&gt;

&lt;p&gt;The same pattern appears in industrial monitoring, smart-home devices and Internet of Things applications:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Collect sensor data.&lt;/li&gt;
&lt;li&gt;Validate incoming measurements.&lt;/li&gt;
&lt;li&gt;Apply detection logic.&lt;/li&gt;
&lt;li&gt;Identify abnormal conditions.&lt;/li&gt;
&lt;li&gt;Communicate an actionable warning.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Reliable monitoring systems need to consider sensor errors, communication failures and the possibility of false alarms.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Direct and indirect TPMS systems use different methods to identify potential tyre-pressure problems. Both demonstrate how sensors and software can help drivers make more informed decisions.&lt;/p&gt;

&lt;p&gt;Technology is most effective when users understand its limitations and combine automated alerts with appropriate physical inspections.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This article is for educational purposes. Follow the vehicle manufacturer's instructions for tyre pressure and TPMS maintenance.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Digital Imaging in Healthcare: From Sensor to Clinical Image</title>
      <dc:creator>freelancing</dc:creator>
      <pubDate>Sun, 18 Oct 2026 15:34:19 +0000</pubDate>
      <link>https://dev.to/freelancing_2b362430a47f8/digital-imaging-in-healthcare-from-sensor-to-clinical-image-lhm</link>
      <guid>https://dev.to/freelancing_2b362430a47f8/digital-imaging-in-healthcare-from-sensor-to-clinical-image-lhm</guid>
      <description>&lt;p&gt;Digital imaging is an important part of modern healthcare. It allows information captured by imaging equipment to be converted into a digital representation that can be viewed, stored and reviewed by qualified professionals.&lt;/p&gt;

&lt;p&gt;Understanding the general workflow helps explain how hardware and software work together to produce useful clinical images.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Capturing the Signal
&lt;/h2&gt;

&lt;p&gt;A digital imaging system starts with a detector. Depending on the technology, the detector records incoming energy and converts it into an electrical signal.&lt;/p&gt;

&lt;p&gt;In digital dental radiography, for example, an intraoral sensor detects X-rays that have passed through the relevant structures. The sensor's response varies according to the energy reaching different parts of its surface.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Converting the Signal into Data
&lt;/h2&gt;

&lt;p&gt;The detector's electrical response is converted into numerical data using electronic processing and analogue-to-digital conversion.&lt;/p&gt;

&lt;p&gt;Each pixel in the resulting image represents a sampled measurement. The range of recorded values depends on the sensor, exposure conditions and processing pipeline.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Image Processing
&lt;/h2&gt;

&lt;p&gt;Software may apply corrections that compensate for detector characteristics or improve the presentation of the image.&lt;/p&gt;

&lt;p&gt;Common operations in digital imaging include brightness adjustment, contrast enhancement and noise reduction. These processes can make information easier to view, but they cannot reliably recover every detail that was never captured.&lt;/p&gt;

&lt;p&gt;Image processing should preserve clinically relevant information rather than create a misleading appearance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Storage and Display
&lt;/h2&gt;

&lt;p&gt;The processed image is displayed on a monitor and stored using suitable software and file formats.&lt;/p&gt;

&lt;p&gt;Healthcare systems must consider data integrity, access permissions, privacy and reliable retrieval. Image metadata may also contain information needed to interpret or manage the study.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Professional Interpretation
&lt;/h2&gt;

&lt;p&gt;A digital image is not a diagnosis by itself. Its meaning depends on the imaging technique, the quality of the capture and the clinical context.&lt;/p&gt;

&lt;p&gt;Qualified healthcare professionals interpret the image alongside relevant examination findings and other information.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Quality Assurance Matters
&lt;/h2&gt;

&lt;p&gt;Image quality can be affected by detector condition, positioning, exposure settings, movement and software processing. Healthcare facilities use appropriate procedures to reduce avoidable errors and maintain equipment performance.&lt;/p&gt;

&lt;p&gt;In dental imaging, radiation exposure should also follow the applicable clinical justification and optimisation principles.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Digital imaging combines sensors, electronics, software and professional interpretation. Understanding this pipeline provides a useful foundation for studying medical technology, image processing and healthcare information systems.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Building a Home Loan Calculator in Python</title>
      <dc:creator>freelancing</dc:creator>
      <pubDate>Sun, 18 Oct 2026 15:33:48 +0000</pubDate>
      <link>https://dev.to/freelancing_2b362430a47f8/building-a-home-loan-calculator-in-python-3cf9</link>
      <guid>https://dev.to/freelancing_2b362430a47f8/building-a-home-loan-calculator-in-python-3cf9</guid>
      <description>&lt;p&gt;A home loan calculator is a useful programming project for practising input validation, arithmetic, functions and formatted output.&lt;/p&gt;

&lt;p&gt;This tutorial demonstrates a simplified repayment calculator using Python. It estimates a regular monthly repayment for a loan with a fixed interest rate and monthly repayments.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Formula
&lt;/h2&gt;

&lt;p&gt;For a standard amortising loan, the monthly repayment can be calculated using:&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
M = \frac{P r(1+r)^n}{(1+r)^n-1}&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;Where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;(M) is the monthly repayment.&lt;/li&gt;
&lt;li&gt;(P) is the principal loan amount.&lt;/li&gt;
&lt;li&gt;(r) is the monthly interest rate expressed as a decimal.&lt;/li&gt;
&lt;li&gt;(n) is the total number of monthly repayments.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The annual interest rate is divided by 12 and converted from a percentage into a decimal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Python Implementation
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;calculate_monthly_repayment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;principal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;annual_rate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;years&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;principal&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Principal must be positive.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;annual_rate&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Interest rate cannot be negative.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;years&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Loan term must be positive.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;months&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;years&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;
    &lt;span class="n"&gt;monthly_rate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;annual_rate&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;monthly_rate&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;principal&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;months&lt;/span&gt;

    &lt;span class="n"&gt;factor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;monthly_rate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="n"&gt;months&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;principal&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;monthly_rate&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;factor&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;factor&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;principal&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Loan amount: &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;annual_rate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;float&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Annual interest rate (%): &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;years&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Loan term (years): &lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

    &lt;span class="n"&gt;repayment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;calculate_monthly_repayment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;principal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;annual_rate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;years&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Estimated monthly repayment: $&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;repayment&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;,.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="nb"&gt;ValueError&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Invalid input: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How the Code Works
&lt;/h2&gt;

&lt;p&gt;The function validates the loan amount, interest rate and term before performing the calculation.&lt;/p&gt;

&lt;p&gt;It converts the annual rate into a monthly decimal rate and calculates the number of monthly repayments. If the interest rate is zero, it divides the principal equally across the repayment period.&lt;/p&gt;

&lt;p&gt;Otherwise, it applies the amortisation formula to estimate the monthly repayment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing the Calculator
&lt;/h2&gt;

&lt;p&gt;Try different loan amounts, rates and terms. Check that increasing the interest rate generally increases the repayment, while extending the term generally reduces the regular repayment but may increase the total interest paid.&lt;/p&gt;

&lt;h2&gt;
  
  
  Important Limitations
&lt;/h2&gt;

&lt;p&gt;This is an educational example. It assumes a constant interest rate and regular monthly repayments. It does not account for fees, offset accounts, redraw facilities, changing rates or lender-specific repayment rules.&lt;/p&gt;

&lt;p&gt;Real loan products can differ substantially, so the output should not be treated as a lender quotation or personal financial advice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This project demonstrates how mathematical formulas can be converted into reusable Python functions. It can be extended with a graphical interface, an amortisation schedule, unit tests or a chart of the remaining balance over time.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Pool Filtration as a Flow-Control System: Understanding the Basics</title>
      <dc:creator>freelancing</dc:creator>
      <pubDate>Sun, 18 Oct 2026 15:33:20 +0000</pubDate>
      <link>https://dev.to/freelancing_2b362430a47f8/pool-filtration-as-a-flow-control-system-understanding-the-basics-o6m</link>
      <guid>https://dev.to/freelancing_2b362430a47f8/pool-filtration-as-a-flow-control-system-understanding-the-basics-o6m</guid>
      <description>&lt;p&gt;Swimming pool filtration can be understood as a simple flow-control system. Water moves through pipes, passes through a filter and returns to the pool, while the circulation system helps distribute treated water.&lt;/p&gt;

&lt;p&gt;Understanding this process makes it easier to recognise why flow, filtration and routine equipment checks matter.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Main Components
&lt;/h2&gt;

&lt;p&gt;A typical pool circulation system contains several interconnected components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pump:&lt;/strong&gt; Moves water through the circulation loop.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Skimmer and suction points:&lt;/strong&gt; Collect water from the pool.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Filter:&lt;/strong&gt; Captures suspended particles from the circulating water.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Return lines:&lt;/strong&gt; Direct filtered water back into the pool.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Valves:&lt;/strong&gt; Control or redirect water flow.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The exact arrangement varies depending on the pool and its equipment.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Happens During Filtration?
&lt;/h2&gt;

&lt;p&gt;The pump draws water into the circulation system. Water then passes through the filter medium, which captures particles according to the filter's design.&lt;/p&gt;

&lt;p&gt;The filtered water returns to the pool, helping maintain circulation and distribute treated water.&lt;/p&gt;

&lt;p&gt;Filtration does not replace sanitisation. A pool needs an appropriate treatment system and properly maintained water chemistry in addition to mechanical filtration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Flow Rate Matters
&lt;/h2&gt;

&lt;p&gt;If water flow becomes restricted, the system may not circulate water as intended. Possible causes include a blocked basket, a dirty filter, a valve problem or an issue with the pump.&lt;/p&gt;

&lt;p&gt;A sudden change in pressure readings or return flow can be a useful sign that an inspection is needed. However, pressure readings vary by system, so they should be interpreted using the equipment manufacturer's guidance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Basic Troubleshooting Principles
&lt;/h2&gt;

&lt;p&gt;When circulation appears abnormal:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Observe whether the pump is operating normally.&lt;/li&gt;
&lt;li&gt;Check accessible baskets for accumulated debris.&lt;/li&gt;
&lt;li&gt;Review the filter's pressure gauge, if fitted.&lt;/li&gt;
&lt;li&gt;Look for visible leaks or unusual noises.&lt;/li&gt;
&lt;li&gt;Follow the manufacturer's instructions before cleaning or servicing equipment.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Switch off and isolate equipment as instructed before maintenance. Never open pressurised filter equipment while it is under pressure.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Pool filtration combines fluid movement, mechanical separation and water treatment. Understanding how these elements work together provides a useful foundation for routine maintenance and recognising unusual equipment behaviour.&lt;/p&gt;

&lt;p&gt;The most reliable approach is to monitor the system consistently and follow the instructions for the specific pump, filter and treatment equipment installed.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Understanding Tyre Pressure Monitoring Systems: Direct vs. Indirect TPMS</title>
      <dc:creator>freelancing</dc:creator>
      <pubDate>Sun, 18 Oct 2026 15:32:28 +0000</pubDate>
      <link>https://dev.to/freelancing_2b362430a47f8/understanding-tyre-pressure-monitoring-systems-direct-vs-indirect-tpms-37p9</link>
      <guid>https://dev.to/freelancing_2b362430a47f8/understanding-tyre-pressure-monitoring-systems-direct-vs-indirect-tpms-37p9</guid>
      <description>&lt;p&gt;Tyre pressure plays an important role in vehicle handling, tyre wear and driving safety. Modern vehicles may use a Tyre Pressure Monitoring System (TPMS) to alert the driver when tyre pressure appears to be too low.&lt;/p&gt;

&lt;p&gt;There are two common approaches: direct TPMS and indirect TPMS.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is Direct TPMS?
&lt;/h2&gt;

&lt;p&gt;A direct TPMS uses pressure sensors, usually installed inside the wheels or attached to the tyre valves, to measure tyre pressure.&lt;/p&gt;

&lt;p&gt;The sensor transmits information to the vehicle's monitoring system. Depending on the vehicle, the driver may see a warning light or individual tyre-pressure readings.&lt;/p&gt;

&lt;h3&gt;
  
  
  Advantages
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Measures tyre pressure directly.&lt;/li&gt;
&lt;li&gt;Some systems display pressure readings for individual tyres.&lt;/li&gt;
&lt;li&gt;Can identify pressure loss without relying solely on wheel-speed differences.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Limitations
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Sensors have batteries that eventually need attention.&lt;/li&gt;
&lt;li&gt;Sensor replacement and servicing may require specialised equipment.&lt;/li&gt;
&lt;li&gt;Wheels must be handled carefully during tyre replacement to avoid damaging sensors.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What Is Indirect TPMS?
&lt;/h2&gt;

&lt;p&gt;An indirect TPMS generally uses wheel-speed information from the vehicle's anti-lock braking system.&lt;/p&gt;

&lt;p&gt;A tyre with lower pressure may have a different rolling circumference from a properly inflated tyre. The system analyses wheel behaviour and looks for patterns that may indicate pressure loss.&lt;/p&gt;

&lt;h3&gt;
  
  
  Advantages
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Does not require a separate pressure sensor inside every tyre.&lt;/li&gt;
&lt;li&gt;Can use existing vehicle sensor systems.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Limitations
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Does not directly measure air pressure.&lt;/li&gt;
&lt;li&gt;Performance depends on the system's design and calibration.&lt;/li&gt;
&lt;li&gt;Some systems require recalibration after pressure adjustments or tyre changes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why Correct Tyre Pressure Still Matters
&lt;/h2&gt;

&lt;p&gt;TPMS is an alerting system, not a replacement for routine inspections. A warning may appear only after pressure has fallen sufficiently, and not every tyre problem produces a warning.&lt;/p&gt;

&lt;p&gt;Drivers should check tyre pressure manually at the intervals recommended by the vehicle manufacturer and investigate recurring warnings.&lt;/p&gt;

&lt;p&gt;Never ignore a warning simply because it disappears after restarting the vehicle.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Direct and indirect TPMS use different methods to identify possible pressure problems, but both are designed to help drivers notice conditions that deserve attention.&lt;/p&gt;

&lt;p&gt;Understanding which system your vehicle uses can make its warnings easier to interpret. Always consult the vehicle handbook for the correct pressure specifications and recommended maintenance procedures.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Digital Imaging in Healthcare: From Sensor to Clinical Image</title>
      <dc:creator>freelancing</dc:creator>
      <pubDate>Thu, 15 Oct 2026 16:19:26 +0000</pubDate>
      <link>https://dev.to/freelancing_2b362430a47f8/digital-imaging-in-healthcare-from-sensor-to-clinical-image-50aa</link>
      <guid>https://dev.to/freelancing_2b362430a47f8/digital-imaging-in-healthcare-from-sensor-to-clinical-image-50aa</guid>
      <description>&lt;p&gt;Digital imaging is used across healthcare to help professionals examine structures that cannot be fully assessed through direct observation alone. Dental radiography is one example of a system that combines physical sensors, digital processing and image interpretation.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Digital Image Capture Works
&lt;/h2&gt;

&lt;p&gt;In digital radiography, an X-ray source produces radiation that passes through the region being examined. Different tissues attenuate the radiation to different degrees.&lt;/p&gt;

&lt;p&gt;A digital detector records the resulting signal and converts it into image data. Software processes this data so that the image can be displayed on a computer.&lt;/p&gt;

&lt;p&gt;The resulting image provides information about structures that may not be visible during an ordinary visual examination.&lt;/p&gt;

&lt;h2&gt;
  
  
  From Signal to Pixels
&lt;/h2&gt;

&lt;p&gt;A digital image consists of pixels, each representing a measured signal that has been mapped to an intensity value.&lt;/p&gt;

&lt;p&gt;The detector's characteristics, image resolution and processing methods influence the appearance of the final image.&lt;/p&gt;

&lt;p&gt;Increasing image contrast may make certain features easier to distinguish, but image enhancement cannot recover information that was never captured by the detector.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Image Quality Matters
&lt;/h2&gt;

&lt;p&gt;Image quality can be affected by patient positioning, movement, detector placement and exposure settings.&lt;/p&gt;

&lt;p&gt;A poorly positioned image may not show the required anatomy clearly. Depending on the clinical need, the professional may decide whether another image or a different assessment method is appropriate.&lt;/p&gt;

&lt;p&gt;Image interpretation must also consider the patient's history and clinical examination. A digital image is not a diagnosis by itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Data Storage and Privacy
&lt;/h2&gt;

&lt;p&gt;Digital images can be stored alongside clinical records and retrieved when needed. This can support continuity of care and communication between authorised healthcare professionals.&lt;/p&gt;

&lt;p&gt;However, these records contain sensitive information. Systems must use appropriate access controls, secure storage and responsible data-handling practices.&lt;/p&gt;

&lt;p&gt;Images should not be shared publicly without proper authorisation and suitable privacy protections.&lt;/p&gt;

&lt;h2&gt;
  
  
  Radiation Safety
&lt;/h2&gt;

&lt;p&gt;Dental X-rays use ionising radiation. Imaging should be selected when clinically justified, using appropriate procedures and exposure settings.&lt;/p&gt;

&lt;p&gt;Digital technology does not remove the need for radiation-safety principles or professional judgement.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Digital dental imaging illustrates how sensor technology and software support healthcare examinations. Its usefulness depends on appropriate image acquisition, careful interpretation, privacy protection and responsible clinical decision-making.&lt;/p&gt;

&lt;p&gt;This article is for educational purposes and does not provide medical or dental advice.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Building a Home Loan Calculator in Python</title>
      <dc:creator>freelancing</dc:creator>
      <pubDate>Thu, 15 Oct 2026 16:18:27 +0000</pubDate>
      <link>https://dev.to/freelancing_2b362430a47f8/building-a-home-loan-calculator-in-python-o0f</link>
      <guid>https://dev.to/freelancing_2b362430a47f8/building-a-home-loan-calculator-in-python-o0f</guid>
      <description>&lt;p&gt;A home loan calculator is a useful programming project for learning about user input, mathematical formulas, validation and formatted output.&lt;/p&gt;

&lt;p&gt;This example calculates the estimated monthly repayment for a standard principal-and-interest loan with a fixed interest rate.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Formula
&lt;/h2&gt;

&lt;p&gt;Let:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;(P) = principal borrowed&lt;/li&gt;
&lt;li&gt;(r) = monthly interest rate&lt;/li&gt;
&lt;li&gt;(n) = total number of monthly repayments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The monthly repayment (M) is:&lt;/p&gt;

&lt;p&gt;[&lt;br&gt;
M=P\frac{r(1+r)^n}{(1+r)^n-1}&lt;br&gt;
]&lt;/p&gt;

&lt;p&gt;When the interest rate is zero, the repayment is simply the principal divided by the number of payments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Python Implementation
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;calculate_monthly_repayment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;principal&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;annual_rate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;years&lt;/span&gt;
&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;principal&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Principal must be positive.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;annual_rate&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Interest rate cannot be negative.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;years&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Loan term must be positive.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;months&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;years&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;
    &lt;span class="n"&gt;monthly_rate&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;annual_rate&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mi"&gt;12&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;monthly_rate&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;principal&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;months&lt;/span&gt;

    &lt;span class="n"&gt;factor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;monthly_rate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt; &lt;span class="n"&gt;months&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;principal&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;monthly_rate&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;factor&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;factor&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;


&lt;span class="n"&gt;payment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;calculate_monthly_repayment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;principal&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;400000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;annual_rate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;years&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;30&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Estimated monthly repayment: $&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;payment&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;,.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How the Code Works
&lt;/h2&gt;

&lt;p&gt;First, the function validates the inputs. This prevents invalid values, such as a negative principal or zero-year loan term.&lt;/p&gt;

&lt;p&gt;Next, it converts the annual percentage rate into a monthly decimal rate and converts the loan term into months.&lt;/p&gt;

&lt;p&gt;The formula then calculates the scheduled monthly repayment.&lt;/p&gt;

&lt;p&gt;For the example above, the result is approximately $2,398 per month.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing the Calculator
&lt;/h2&gt;

&lt;p&gt;A useful next step is to test several cases:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A different principal amount.&lt;/li&gt;
&lt;li&gt;A shorter loan term.&lt;/li&gt;
&lt;li&gt;A zero-interest loan.&lt;/li&gt;
&lt;li&gt;Invalid inputs.&lt;/li&gt;
&lt;li&gt;Very small interest rates.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;You can also extend the program to generate an amortisation schedule showing the interest and principal portions of each payment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Important Limitations
&lt;/h2&gt;

&lt;p&gt;This example assumes a fixed rate and regular monthly repayments. Actual Australian home loans may use daily interest calculations, variable rates, fees, offset accounts and other product-specific conditions.&lt;/p&gt;

&lt;p&gt;The result is an educational estimate, not a lender quote or financial recommendation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;A loan calculator demonstrates how a real-world financial concept can be translated into a mathematical model and a reusable Python function. It is also a good foundation for learning unit testing and building a simple web application.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Pool Filtration as a Flow-Control System: Understanding the Basics</title>
      <dc:creator>freelancing</dc:creator>
      <pubDate>Thu, 15 Oct 2026 16:17:28 +0000</pubDate>
      <link>https://dev.to/freelancing_2b362430a47f8/pool-filtration-as-a-flow-control-system-understanding-the-basics-3do3</link>
      <guid>https://dev.to/freelancing_2b362430a47f8/pool-filtration-as-a-flow-control-system-understanding-the-basics-3do3</guid>
      <description>&lt;p&gt;A swimming pool circulation system is a practical example of fluid mechanics. It moves water through a network of pipes and equipment to support filtration and water treatment.&lt;/p&gt;

&lt;p&gt;Understanding the system as a flow-control loop makes it easier to see how individual components interact.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Main Components
&lt;/h2&gt;

&lt;p&gt;A typical circulation system includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Intake points:&lt;/strong&gt; Collect water from the pool.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pump:&lt;/strong&gt; Creates the pressure difference needed to move water.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Filter:&lt;/strong&gt; Removes suspended particles.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Return outlets:&lt;/strong&gt; Direct filtered water back into the pool.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Valves and plumbing:&lt;/strong&gt; Control and route water through the system.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The exact arrangement depends on the pool and its equipment.&lt;/p&gt;

&lt;h2&gt;
  
  
  Flow Rate and Resistance
&lt;/h2&gt;

&lt;p&gt;Water flow depends on the pump's characteristics and the resistance of the plumbing network.&lt;/p&gt;

&lt;p&gt;Pipe length, pipe diameter, bends, valves and filter condition can influence resistance. As resistance increases, the operating flow rate may decrease for a given pump.&lt;/p&gt;

&lt;p&gt;This is why selecting a pump based only on its advertised maximum flow rate can be misleading. Actual performance depends on the complete system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Filter Condition Matters
&lt;/h2&gt;

&lt;p&gt;A filter collects particles as water passes through it. As material accumulates, resistance may increase and flow may change.&lt;/p&gt;

&lt;p&gt;Different filter designs require different cleaning methods. Sand filters may use backwashing, while cartridge filters generally require removal and cleaning according to manufacturer instructions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Diagnosing Flow Problems
&lt;/h2&gt;

&lt;p&gt;Reduced circulation can have multiple causes, including blocked baskets, valve settings, air entering the system, a dirty filter or a pump issue.&lt;/p&gt;

&lt;p&gt;A single symptom does not identify the cause. Equipment readings, safe inspections and manufacturer guidance help narrow down the possibilities.&lt;/p&gt;

&lt;h2&gt;
  
  
  Energy Efficiency
&lt;/h2&gt;

&lt;p&gt;Pump selection and operating schedules affect energy consumption. Variable-speed pumps, where suitable, can allow flow to be adjusted to the task.&lt;/p&gt;

&lt;p&gt;However, operating settings must still meet the pool's filtration and treatment requirements. Reducing energy use should not compromise water quality.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Pool circulation combines pump performance, hydraulic resistance and filtration. Understanding these relationships provides a useful foundation for troubleshooting and maintaining the system.&lt;/p&gt;

&lt;p&gt;This is general educational information. Pool equipment should be installed and maintained according to manufacturer instructions and applicable safety requirements.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Understanding Tyre Pressure Monitoring Systems: Direct vs Indirect TPMS</title>
      <dc:creator>freelancing</dc:creator>
      <pubDate>Thu, 15 Oct 2026 16:15:47 +0000</pubDate>
      <link>https://dev.to/freelancing_2b362430a47f8/understanding-tyre-pressure-monitoring-systems-direct-vs-indirect-tpms-44k0</link>
      <guid>https://dev.to/freelancing_2b362430a47f8/understanding-tyre-pressure-monitoring-systems-direct-vs-indirect-tpms-44k0</guid>
      <description>&lt;p&gt;Tyre Pressure Monitoring Systems (TPMS) help drivers identify potential tyre-pressure problems. These systems are an interesting example of how sensors, embedded electronics and software work together in modern vehicles.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is TPMS?
&lt;/h2&gt;

&lt;p&gt;TPMS monitors tyre pressure or estimates pressure-related changes and alerts the driver when the system detects a potential issue.&lt;/p&gt;

&lt;p&gt;There are two common approaches: direct and indirect monitoring.&lt;/p&gt;

&lt;h2&gt;
  
  
  Direct TPMS
&lt;/h2&gt;

&lt;p&gt;A direct TPMS typically uses pressure sensors installed inside the wheels. These sensors measure tyre pressure and communicate readings to the vehicle's monitoring system.&lt;/p&gt;

&lt;p&gt;Advantages include direct pressure measurements and the ability of many systems to identify which tyre requires attention.&lt;/p&gt;

&lt;p&gt;However, sensor batteries, replacement procedures and communication faults can affect operation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Indirect TPMS
&lt;/h2&gt;

&lt;p&gt;An indirect system uses wheel-speed sensors, often associated with the anti-lock braking system. An underinflated tyre may have a different effective rolling circumference, causing a change in wheel rotation.&lt;/p&gt;

&lt;p&gt;The system analyses these differences to identify a possible pressure problem.&lt;/p&gt;

&lt;p&gt;Indirect systems do not directly measure the air pressure inside each tyre, and their capabilities vary by vehicle.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Software Matters
&lt;/h2&gt;

&lt;p&gt;TPMS demonstrates how software interprets sensor readings and converts them into information that drivers can understand.&lt;/p&gt;

&lt;p&gt;The system must account for normal operating variations and distinguish potential faults from expected behaviour. Depending on the design, calibration and reset procedures may also be required.&lt;/p&gt;

&lt;h2&gt;
  
  
  Important Limitations
&lt;/h2&gt;

&lt;p&gt;TPMS does not replace manual pressure checks or tyre inspections. It may not detect every puncture, structural defect or pressure problem immediately.&lt;/p&gt;

&lt;p&gt;Drivers should follow the vehicle manufacturer's instructions and investigate warning lights rather than ignoring them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Direct and indirect TPMS use different methods to identify potential tyre-pressure issues. Understanding the difference illustrates how automotive sensors and embedded software contribute to vehicle safety.&lt;/p&gt;

&lt;p&gt;This article is educational and does not replace vehicle-specific maintenance guidance.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
