<?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: Ikegbo Ogochukwu</title>
    <description>The latest articles on DEV Community by Ikegbo Ogochukwu (@kenryikegbo).</description>
    <link>https://dev.to/kenryikegbo</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%2F419033%2Faf7bdc0a-e5fb-4d05-a32c-661fa8d1bca5.png</url>
      <title>DEV Community: Ikegbo Ogochukwu</title>
      <link>https://dev.to/kenryikegbo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kenryikegbo"/>
    <language>en</language>
    <item>
      <title>How to Convert Bash Kaggle Commands to PowerShell (Without Breaking Your Setup)</title>
      <dc:creator>Ikegbo Ogochukwu</dc:creator>
      <pubDate>Thu, 10 Sep 2026 14:17:16 +0000</pubDate>
      <link>https://dev.to/kenryikegbo/how-to-convert-bash-kaggle-commands-to-powershell-without-breaking-your-setup-1ek6</link>
      <guid>https://dev.to/kenryikegbo/how-to-convert-bash-kaggle-commands-to-powershell-without-breaking-your-setup-1ek6</guid>
      <description>&lt;h2&gt;
  
  
  How to Convert Bash Kaggle Commands to PowerShell (Without Breaking Your Setup)
&lt;/h2&gt;

&lt;p&gt;If you have ever tried to follow a machine learning tutorial on Windows, you have probably run into a Bash script that looks exactly like this:&lt;/p&gt;

&lt;p&gt;mkdir -p ~/.kaggle &amp;amp;&amp;amp; echo "YOUR_TOKEN" &amp;gt; ~/.kaggle/access_token &amp;amp;&amp;amp; chmod 600 ~/.kaggle/access_token&lt;/p&gt;

&lt;p&gt;You paste it into PowerShell, hit enter, and... Boom. Red error text everywhere. 💥&lt;/p&gt;

&lt;h2&gt;
  
  
  Windows handles file paths, environment variables, and file permissions completely differently than Linux or macOS. If you need to translate that exact Bash one-liner into clean, native PowerShell, here is how you do it step-by-step.
&lt;/h2&gt;

&lt;h2&gt;
  
  
  The PowerShell Equivalent
&lt;/h2&gt;

&lt;p&gt;Open your PowerShell window and run this block of code:&lt;/p&gt;

&lt;h1&gt;
  
  
  1. Create the directory safely (acts like mkdir -p)
&lt;/h1&gt;

&lt;p&gt;New-Item -ItemType Directory -Force -Path "$HOME.kaggle"&lt;/p&gt;

&lt;h1&gt;
  
  
  2. Write the token to the file (acts like echo &amp;gt;)
&lt;/h1&gt;

&lt;p&gt;Set-Content -Path "$HOME.kaggle\access_token" -Value "KGAT_f84238731c3b8830736ae42599c6ac80"&lt;/p&gt;

&lt;h1&gt;
  
  
  3. Restrict permissions exclusively to your user (acts like chmod 600)
&lt;/h1&gt;

&lt;p&gt;$Acl = Get-Acl -Path "$HOME.kaggle\access_token"&lt;br&gt;
$Acl.SetAccessRuleProtection($true, $false) # Strip away inherited permissions&lt;br&gt;
$AccessRule = New-Object System.Security.AccessControl.FileSystemAccessRule($env:USERNAME, "FullControl", "Allow")&lt;br&gt;
$Acl.AddAccessRule($AccessRule)&lt;br&gt;
Set-Acl -Path "$HOME.kaggle\access_token" -AclObject $Acl&lt;/p&gt;




&lt;h2&gt;
  
  
  🔍 Breaking Down the Differences## 1. File Paths (~ vs $HOME)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;In Bash: ~ points directly to your home directory (/home/username).&lt;/li&gt;
&lt;li&gt;In PowerShell: While PowerShell supports ~ in some commands, it can be unpredictable in scripts. Using $HOME points cleanly to your Windows user profile (typically C:\Users\YourName).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  2. Creating Folders (mkdir -p vs New-Item -Force)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;In Bash: mkdir -p ensures the folder is created and prevents errors if it already exists.&lt;/li&gt;
&lt;li&gt;In PowerShell: New-Item -ItemType Directory -Force does the exact same thing. The -Force parameter prevents PowerShell from throwing an error if the .kaggle folder is already there.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  3. Writing Files (echo &amp;gt; vs Set-Content)
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;In Bash: echo token &amp;gt; file creates or overwrites a file with the string text.&lt;/li&gt;
&lt;li&gt;In PowerShell: While echo "token" &amp;gt; file technically works in PowerShell, it often encodes the file in UTF-16 LE, which causes weird character parsing errors with API clients. Set-Content ensures a cleaner, standard string delivery.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  4. Permissions (chmod 600 vs Windows ACL)
&lt;/h2&gt;

&lt;p&gt;This is where developers usually get stuck. Windows does not use POSIX bitmask permissions (600, 755, etc.). It uses an Access Control List (ACL).&lt;br&gt;
chmod 600 means: "Only the file owner can read/write this file. Everyone else gets nothing."&lt;br&gt;
To do this in Windows, our script:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Uses SetAccessRuleProtection($true, $false) to block inherited permissions from the parent folder (which normally lets administrators or other users read it).&lt;/li&gt;
&lt;li&gt;Explicitly grants Full Control exclusively to your active Windows username ($env:USERNAME).&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  💡 Pro-Tip: Exporting the Config Directory
&lt;/h2&gt;

&lt;p&gt;Many Kaggle API tools look for a kaggle.json file inside a directory path stored in your environment variables.&lt;br&gt;
If you need to quickly tell your session where to look for your credentials, you can set an environment variable using this command:&lt;/p&gt;

&lt;h1&gt;
  
  
  For the current session only:
&lt;/h1&gt;

&lt;p&gt;$env:KAGGLE_CONFIG_DIR = "$HOME.kaggle"&lt;/p&gt;

&lt;h1&gt;
  
  
  To make it permanent across all future sessions:
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Note: If you run the permanent command, make sure to restart your PowerShell window for it to take effect!
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Wrap Up
&lt;/h2&gt;

&lt;p&gt;Switching back and forth between terminal syntaxes can be a headache, but learning how PowerShell processes paths and ACL objects will save you hours of debugging when deploying local data science environments on Windows.&lt;/p&gt;

&lt;h2&gt;
  
  
  Happy coding! 🚀
&lt;/h2&gt;

</description>
      <category>ai</category>
      <category>kaggle</category>
      <category>bash</category>
      <category>googlecloud</category>
    </item>
    <item>
      <title>How to Set Up n8n Locally with Docker Desktop:</title>
      <dc:creator>Ikegbo Ogochukwu</dc:creator>
      <pubDate>Tue, 01 Sep 2026 17:20:24 +0000</pubDate>
      <link>https://dev.to/kenryikegbo/how-to-set-up-n8n-locally-with-docker-desktop-l23</link>
      <guid>https://dev.to/kenryikegbo/how-to-set-up-n8n-locally-with-docker-desktop-l23</guid>
      <description>&lt;p&gt;This complete beginner's guide walks through every step to prepare your computer, install Docker Desktop, and run n8n locally with persistent storage.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Check System Requirements and Enable Virtualization
&lt;/h2&gt;

&lt;p&gt;Docker requires hardware virtualization enabled in your computer's BIOS/UEFI to run containers.&lt;/p&gt;

&lt;h3&gt;
  
  
  Check on Windows:
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;Press &lt;code&gt;Ctrl + Shift + Esc&lt;/code&gt; to open &lt;strong&gt;Task Manager&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Click the &lt;strong&gt;Performance&lt;/strong&gt; tab, then select &lt;strong&gt;CPU&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Look at the bottom-right for &lt;strong&gt;Virtualization: Enabled&lt;/strong&gt;. If disabled, enable Intel VT-x / AMD-V in your BIOS.&lt;/li&gt;
&lt;li&gt;Open &lt;strong&gt;PowerShell&lt;/strong&gt; as Administrator and run:&lt;/li&gt;
&lt;/ol&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
powershell
   wsl --install
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>n8nbrightdatachallenge</category>
      <category>docker</category>
      <category>containers</category>
      <category>automation</category>
    </item>
    <item>
      <title>I Built a Soil Fertility AI Pipeline That Runs on a Raspberry Pi 5 — Here's How</title>
      <dc:creator>Ikegbo Ogochukwu</dc:creator>
      <pubDate>Tue, 01 Sep 2026 09:54:19 +0000</pubDate>
      <link>https://dev.to/kenryikegbo/i-built-a-soil-fertility-ai-pipeline-that-runs-on-a-raspberry-pi-5-heres-how-338m</link>
      <guid>https://dev.to/kenryikegbo/i-built-a-soil-fertility-ai-pipeline-that-runs-on-a-raspberry-pi-5-heres-how-338m</guid>
      <description>&lt;p&gt;&lt;strong&gt;An end-to-end walkthrough of training a CNN on soil images, fusing predictions with synthetic sensor data, and deploying to the edge — including every gotcha.&lt;/strong&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Our "5G in Agriculture" project required building a full soil fertility assessment pipeline: multi-parameter sensors, GPS-based spatial mapping, deep learning inference, and a cloud dashboard — all running on a Raspberry Pi 5 edge device.&lt;/p&gt;

&lt;p&gt;Since we don't have real sensor hardware yet, and haven't visited any farmland, we needed the entire system to be testable &lt;em&gt;right now&lt;/em&gt; from my desk — without sacrificing fidelity. So I combined &lt;strong&gt;synthetic sensor data&lt;/strong&gt; with a &lt;strong&gt;custom CNN trained on public soil image datasets&lt;/strong&gt;, fused both streams at inference time, and served results through a live web dashboard.&lt;/p&gt;

&lt;p&gt;Here's the complete story — architecture, code, results, and the things that almost didn't work.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌───────────────(one-time)──────────────┐   ┌──────────────(continuous)─────────────┐
│  train_all.py                         │   │  run_edge.py                           │
│                                       │   │                                        │
│  data/download.py    ──────────────┐  │   │  SimulatedSensor                       │
│         ↓                          │  │   │      ↓ NPK / pH / moisture             │
│  model/train_image.py  ────────────┼──┼──→  edge/infer_loop.py                     │
│         ↓                          │  │   │      ↓ MLP (windowed readings)         │
│  models/*.pt          ← Model file →│  │   │      ↓ (optional) Camera frame         │
└───────────────training──────────────┘  │   │            ↓ Image CNN                 │
                                         │   │      ↓ Late Fusion                      │
┌────────────────────────────────────────┘   │   │            ↓ MQTT                   │
│  web/app.py           ← Dashboard         │   │            ↓ Publish                  │
│         ↓                                 │   │                                        │
│  Flask server: / /map /history /settings │   └────────────────────────────────────────┘
└──────────────────────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two independent pipelines feeding into one decision:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Sensor branch:&lt;/strong&gt; Sliding window of 12 recent readings → &lt;code&gt;sklearn&lt;/code&gt; MLPClassifier → class probability vector&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Image branch:&lt;/strong&gt; Real soil photograph → Pure-PyTorch MobileNetV3-style CNN → class probability vector&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fusion:&lt;/strong&gt; Weighted average (&lt;code&gt;0.7 × sensor + 0.3 × image&lt;/code&gt;) → final prediction&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both produce &lt;code&gt;(High, Low, Moderate)&lt;/code&gt; softmax vectors, so fusion is just element-wise weighted averaging — simple, interpretable, reversible.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Pure PyTorch (Not TensorFlow or ONNX)
&lt;/h2&gt;

&lt;p&gt;A common mistake is reaching for TensorFlow first. On this stack, it was broken:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Framework&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;TF 2.21 + Python 3.13&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Broken&lt;/strong&gt; — ABI mismatch on Windows DLLs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ONNX Runtime&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Broken&lt;/strong&gt; — same VC++ redistributable issue&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;torchvision&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Unavailable&lt;/strong&gt; — no wheel for our Python version&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;PyTorch CPU&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;Working&lt;/strong&gt; — pure Python ops, TorchScript export&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The fix was straightforward: build a custom CNN entirely from &lt;code&gt;torch.nn&lt;/code&gt; primitives (no &lt;code&gt;torchvision&lt;/code&gt;). Trained from scratch on public soil image datasets, exported as a TorchScript &lt;code&gt;.pt&lt;/code&gt; file — zero Python dependency at inference time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Training Results
&lt;/h2&gt;

&lt;p&gt;Dataset: &lt;a href="https://github.com/Phantom-fs/Soil-Classification-Dataset" rel="noopener noreferrer"&gt;Phantom-fs/Soil-Classification-Dataset&lt;/a&gt; (7 soil types → mapped to 3 fertility tiers via agricultural science):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tier&lt;/th&gt;
&lt;th&gt;Soil Types&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;Alluvial, Black&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Moderate&lt;/td&gt;
&lt;td&gt;Red, Yellow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;Laterite, Arid, Mountain&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  SoilCNN Architecture
&lt;/h3&gt;

&lt;p&gt;~0.6M parameters. Inspired by MobileNetV3-Small but built from scratch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SoilCNN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Module&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__init__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;num_classes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;img_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;224&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="c1"&gt;# Stem: Conv2d(3→16, k=3, s=2, p=1) → BN → HardSwish()
&lt;/span&gt;        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;stem&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Sequential&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;
        &lt;span class="c1"&gt;# Body: 7 stages of DepthwiseSeparableConv blocks
&lt;/span&gt;        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;body&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Sequential&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;# Head: Conv2d(320→1280, k=1) → BN → HardSwish → GAP → Dropout → FC
&lt;/span&gt;        &lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;head&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;nn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Sequential&lt;/span&gt;&lt;span class="p"&gt;(...)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each body stage uses &lt;code&gt;DepthwiseSeparableConv&lt;/code&gt; internally, which wraps a &lt;code&gt;SEBlock&lt;/code&gt; (Squeeze-and-Excitation) followed by depthwise → pointwise convolution + batch norm + activation. The last block uses HardSwish instead of ReLU to stay closer to MobileNetV3 design principles.&lt;/p&gt;

&lt;h3&gt;
  
  
  Metrics
&lt;/h3&gt;

&lt;p&gt;After 30 epochs (Adam, cosine annealing LR, class-weighted loss):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Class&lt;/th&gt;
&lt;th&gt;Precision&lt;/th&gt;
&lt;th&gt;Recall&lt;/th&gt;
&lt;th&gt;F1&lt;/th&gt;
&lt;th&gt;Support&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;High&lt;/td&gt;
&lt;td&gt;0.98&lt;/td&gt;
&lt;td&gt;0.98&lt;/td&gt;
&lt;td&gt;0.98&lt;/td&gt;
&lt;td&gt;445&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;td&gt;0.96&lt;/td&gt;
&lt;td&gt;0.95&lt;/td&gt;
&lt;td&gt;0.96&lt;/td&gt;
&lt;td&gt;280&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Moderate&lt;/td&gt;
&lt;td&gt;0.99&lt;/td&gt;
&lt;td&gt;0.99&lt;/td&gt;
&lt;td&gt;0.99&lt;/td&gt;
&lt;td&gt;533&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Overall&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;0.98&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1258&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Validation accuracy peaked at &lt;strong&gt;98.4%&lt;/strong&gt;. Not production-grade for soil science (real lab validation would require thousands of annotated field photographs), but strong enough to demonstrate the dual-stream pipeline end-to-end.&lt;/p&gt;

&lt;p&gt;Export: &lt;code&gt;models/soil_image_model.pt&lt;/code&gt; — a 3 MB TorchScript file ready for the Pi.&lt;/p&gt;

&lt;h2&gt;
  
  
  What You Can Actually Test Right Now
&lt;/h2&gt;

&lt;p&gt;With &lt;code&gt;--simulate&lt;/code&gt;, the entire system runs without hardware:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Terminal 1 — inference loop with simulated sensors + synthetic camera&lt;/span&gt;
python run_edge.py &lt;span class="nt"&gt;--simulate&lt;/span&gt; &lt;span class="nt"&gt;--map&lt;/span&gt; &lt;span class="nt"&gt;--map-walk&lt;/span&gt; &lt;span class="nt"&gt;--sim-demo&lt;/span&gt; &lt;span class="nt"&gt;--camera-demo&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--period&lt;/span&gt; 1

&lt;span class="c"&gt;# Terminal 2 — web dashboard&lt;/span&gt;
python run_web.py
&lt;span class="c"&gt;# Open http://localhost:5000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This produces:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A live IDW-mapped PNG showing high/moderate/low zones across the farm&lt;/li&gt;
&lt;li&gt;JSON-per-line logs pushed to MQTT&lt;/li&gt;
&lt;li&gt;A Flask dashboard with latest map, table of predictions, colour-feature stats&lt;/li&gt;
&lt;li&gt;CSV with 15 columns: timestamp, lat, lon, score, class, confidence, img_label, img_conf, L*, a*, b*, dark_colour_index, organic_proxy, moisture_proxy, crack_proxy&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Replace &lt;code&gt;--camera-demo&lt;/code&gt; with &lt;code&gt;--picamera&lt;/code&gt; when you have a PiCamera v3 module connected. The &lt;code&gt;Picamera2Camera&lt;/code&gt; class wraps &lt;code&gt;libcamera&lt;/code&gt; on Raspberry Pi OS Bookworm natively.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploying to the Raspberry Pi 5
&lt;/h2&gt;

&lt;p&gt;The hard part wasn't writing code — it was getting it to &lt;em&gt;run&lt;/em&gt;. Three blockers took most of the effort:&lt;/p&gt;

&lt;h3&gt;
  
  
  Blocker 1: No PyTorch wheels for Python 3.13 on ARM
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ERROR: Could not find a version that satisfies the requirement torch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;PyTorch doesn't ship Python 3.13 ARM wheels yet (as of August 2026). Python 3.13 on the Pi was too bleeding-edge. Fix: install Python 3.11 and use a separate venv.&lt;/p&gt;

&lt;h3&gt;
  
  
  Blocker 2: scikit-image won't compile on Python 3.13 + GCC 14.2.0
&lt;/h3&gt;

&lt;p&gt;When pip tried to build &lt;code&gt;scikit-image&lt;/code&gt; from source, pythran-generated C++ code failed because Pythran uses &lt;code&gt;_v&lt;/code&gt; suffix traits (&lt;code&gt;is_integral_v&lt;/code&gt;) that Debian's GCC 14 headers expose as plain &lt;code&gt;is_integral&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight cpp"&gt;&lt;code&gt;&lt;span class="nl"&gt;error:&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;is_integral_v&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt; &lt;span class="n"&gt;is&lt;/span&gt; &lt;span class="n"&gt;not&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;member&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;std&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;did&lt;/span&gt; &lt;span class="n"&gt;you&lt;/span&gt; &lt;span class="n"&gt;mean&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;is_integral&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fix: pin &lt;code&gt;scikit-image &amp;lt; 0.24&lt;/code&gt; (the 0.23.x series has a pre-built wheel for 3.13) or downgrade to Python 3.11 where both packages have pre-built wheels.&lt;/p&gt;

&lt;h3&gt;
  
  
  Blocker 3: NetworkManager profile secret never persisted to disk
&lt;/h3&gt;

&lt;p&gt;The most frustrating bug. After creating a Wi-Fi connection profile with &lt;code&gt;nmcli&lt;/code&gt;, checking its contents with &lt;code&gt;nmcli -s show&lt;/code&gt; showed the password correctly stored. But the actual config file on disk had &lt;code&gt;psk=&lt;/code&gt; empty:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight ini"&gt;&lt;code&gt;&lt;span class="nn"&gt;[wifi-security]&lt;/span&gt;
&lt;span class="py"&gt;key-mgmt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;wpa-psk&lt;/span&gt;
&lt;span class="py"&gt;psk&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;   &lt;span class="s"&gt;← nothing here&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;NetworkManager reads the file, sees no secret, rejects the connection, and nmcli lies to your face about having saved it. Fix: edit &lt;code&gt;/etc/NetworkManager/system-connections/&amp;lt;profile&amp;gt;.nmconnection&lt;/code&gt; directly and restart NM.&lt;/p&gt;

&lt;p&gt;These three issues alone cost more time than writing the actual pipeline code. Lesson learned: always verify state with &lt;code&gt;cat&lt;/code&gt; before assuming a tool reported truth.&lt;/p&gt;

&lt;h2&gt;
  
  
  File Structure
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;soil_ai/
├── config.py                # Central config: paths, classes, fusion weights
├── requirements.txt
├── run_edge.py              # Edge inference entry point
├── run_web.py               # Web dashboard entry point
├── model/
│   ├── train_image.py       # Train SoilCNN (pure PyTorch) → TorchScript
├── edge/
│   ├── sensors.py           # SimulatedSensor (synthetic NPK/pH/moisture/GPS)
│   ├── mqtt_client.py       # MQTT publisher
│   ├── infer_loop.py        # Main loop: buffer → predict → fuse → publish
│   └── camera.py            # CameraSimulator + Picamera2Camera + preprocessing
├── spatial/
│   ├── live.py              # MapRecorder: CSV + periodic PNG render
│   └── interpolate.py       # IDW interpolation for continuous maps
├── web/
│   ├── app.py               # Flask routes: /, /map, /history, /settings, API
│   └── templates/           # Dashboard, map, history, settings pages
└── outputs/
    ├── predictions.csv      # 15-column log
    ├── farm_live_*.png      # Animated map snapshots
    └── latest_image.jpg     # Latest captured frame
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Next Steps
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Retrain on real labeled data&lt;/strong&gt; when we get to a farm. The crop → fertility mapping is approximate; lab-tested samples are the path to production accuracy.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add EC sensor driver&lt;/strong&gt; in &lt;code&gt;edge/sensors.py&lt;/code&gt;. Currently logged but not modeled (public dataset lacks EC).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Online retraining&lt;/strong&gt; — weekly fine-tuning on newly labeled readings could improve drift performance.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Anomaly detection&lt;/strong&gt; — z-score filtering or autoencoder outlier detection before the MLP catches broken-sensor noise.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;What we built&lt;/th&gt;
&lt;th&gt;How&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Sensor model&lt;/td&gt;
&lt;td&gt;sklearn MLP on sliding windows of 6 features&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Image model&lt;/td&gt;
&lt;td&gt;Pure PyTorch CNN (~0.6M params), TorchScript export&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fusion&lt;/td&gt;
&lt;td&gt;Weighted softmax average (0.7 sensor + 0.3 image)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Spatial mapping&lt;/td&gt;
&lt;td&gt;IDW interpolation → animated PNG heatmaps&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deployment&lt;/td&gt;
&lt;td&gt;Raspberry Pi 5, Picamera2, MQTT, Flask dashboard&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fully testable?&lt;/td&gt;
&lt;td&gt;Yes — &lt;code&gt;--simulate --camera-demo&lt;/code&gt; needs zero hardware&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The full code is in the project repo. Happy to share links if you want to clone and experiment.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Special thanks to everyone who debugged Python 3.13 compatibility issues and NetworkManager race conditions along the way. The code works; the infrastructure fought back.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>programming</category>
      <category>webdev</category>
      <category>python</category>
    </item>
    <item>
      <title>Why Use .then() When Async/Await Is Cleaner?</title>
      <dc:creator>Ikegbo Ogochukwu</dc:creator>
      <pubDate>Tue, 11 Aug 2026 13:05:27 +0000</pubDate>
      <link>https://dev.to/kenryikegbo/why-use-then-when-asyncawait-is-cleaner-1k11</link>
      <guid>https://dev.to/kenryikegbo/why-use-then-when-asyncawait-is-cleaner-1k11</guid>
      <description>&lt;p&gt;series: JavaScript Deep Dives&lt;/p&gt;

&lt;p&gt;If you ask any modern JavaScript developer how to handle asynchronous code, they will almost certainly tell you to use &lt;code&gt;async/await&lt;/code&gt;. It reads like synchronous code, eliminates callback nesting, and works beautifully with standard &lt;code&gt;try/catch&lt;/code&gt; blocks.&lt;/p&gt;

&lt;p&gt;So why does &lt;code&gt;.then()&lt;/code&gt; still exist? Is it just legacy technical debt, or does it actually have legitimate use cases in 2026? &lt;/p&gt;

&lt;p&gt;Let’s look at why &lt;code&gt;.then()&lt;/code&gt; is still a vital tool in your JavaScript toolkit.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Fire-and-Forget Operations (Non-Blocking Tasks)
&lt;/h2&gt;

&lt;p&gt;Sometimes you want to trigger an asynchronous action in the background, but you &lt;strong&gt;don't&lt;/strong&gt; want to pause your main function while waiting for it to finish. &lt;/p&gt;

&lt;p&gt;Imagine a user clicks a button. You need to track an analytics event (async) and immediately redirect them to their dashboard.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Async/Await Approach:
&lt;/h3&gt;

&lt;p&gt;If you use &lt;code&gt;await&lt;/code&gt;, you force the user to wait for the analytics server to respond before they get redirected:&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="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;handleLogin&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// The user is stuck waiting here!&lt;/span&gt;
  &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;trackAnalytics&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;User Logged In&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; 

  &lt;span class="nf"&gt;navigateToDashboard&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;h3&gt;
  
  
  The .then() Solution:
&lt;/h3&gt;

&lt;p&gt;With &lt;code&gt;.then()&lt;/code&gt;, you kick off the analytics call in the background and immediately move the user forward:&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;function&lt;/span&gt; &lt;span class="nf"&gt;handleLogin&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Fires in the background, non-blocking&lt;/span&gt;
  &lt;span class="nf"&gt;trackAnalytics&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;User Logged In&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Logged!&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; 

  &lt;span class="c1"&gt;// Runs instantly!&lt;/span&gt;
  &lt;span class="nf"&gt;navigateToDashboard&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;
  
  
  2. Cleaner Inline Pipelines (Functional Programming)
&lt;/h2&gt;

&lt;p&gt;If you love clean, functional programming pipelines, &lt;code&gt;.then()&lt;/code&gt; allows you to chain pure functions together cleanly without declaring temporary variables.&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="c1"&gt;// Quick, readable data pipeline&lt;/span&gt;
&lt;span class="nf"&gt;fetchUserData&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;extractEmail&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;validateDomain&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;sendWelcomeEmail&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To do this with &lt;code&gt;async/await&lt;/code&gt;, you have to assign a new variable to every single step, which creates a lot of visual boilerplate:&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="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;pipeline&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;user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetchUserData&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;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;extractEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&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;isValid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;validateDomain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;sendWelcomeEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;isValid&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;
  
  
  3. Quick Top-Level Scripts
&lt;/h2&gt;

&lt;p&gt;While modern environments support "Top-Level Await" in ES modules, you still cannot use &lt;code&gt;await&lt;/code&gt; at the root level of older Node.js scripts or legacy CommonJS files without wrapping everything in an Immediately Invoked Function Expression (IIFE).&lt;/p&gt;

&lt;h3&gt;
  
  
  The Async/Await Wrapper:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  The .then() Alternative:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a quick script or a scratchpad file, &lt;code&gt;.then()&lt;/code&gt; gets the job done with zero boilerplate.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Verdict: Use the Right Tool
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;async/await&lt;/code&gt; and &lt;code&gt;.then()&lt;/code&gt; are not enemies—&lt;strong&gt;&lt;code&gt;async/await&lt;/code&gt; is literally built on top of promises.&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;strong&gt;&lt;code&gt;async/await&lt;/code&gt;&lt;/strong&gt; for 90% of your code, especially linear workflows, complex API fetches, and heavy error handling.&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;&lt;code&gt;.then()&lt;/code&gt;&lt;/strong&gt; when you need background tasks, quick one-liners, or functional data pipelines.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What’s your preference? Do you still use &lt;code&gt;.then()&lt;/code&gt; in your projects, or have you completely migrated to &lt;code&gt;async/await&lt;/code&gt;? Let me know in the comments below! 👇&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>programming</category>
      <category>beginners</category>
    </item>
    <item>
      <title>Recovering Wi-Fi Access on a Headless Raspberry Pi with `nmcli`</title>
      <dc:creator>Ikegbo Ogochukwu</dc:creator>
      <pubDate>Tue, 11 Aug 2026 10:05:46 +0000</pubDate>
      <link>https://dev.to/kenryikegbo/recovering-wi-fi-access-on-a-headless-raspberry-pi-with-nmcli-4pcm</link>
      <guid>https://dev.to/kenryikegbo/recovering-wi-fi-access-on-a-headless-raspberry-pi-with-nmcli-4pcm</guid>
      <description>&lt;p&gt;If you manage Raspberry Pis remotely, eventually you'll run into this problem:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;The Raspberry Pi needs new Wi-Fi credentials, but there is no keyboard, monitor, or physical access to configure it.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This happened to me while working with a headless Raspberry Pi. The Pi was connected through SSH, and I needed to update its Wi-Fi credentials without accidentally locking myself out.&lt;/p&gt;

&lt;p&gt;The solution was &lt;strong&gt;NetworkManager + &lt;code&gt;nmcli&lt;/code&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What You'll Need
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Raspberry Pi running Raspberry Pi OS with NetworkManager&lt;/li&gt;
&lt;li&gt;SSH access to the Pi&lt;/li&gt;
&lt;li&gt;Access to the Wi-Fi router/hotspot&lt;/li&gt;
&lt;li&gt;The new Wi-Fi password&lt;/li&gt;
&lt;li&gt;Another computer on the network for SSH&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;NetworkManager treats Wi-Fi configurations as connection profiles. These profiles can be inspected, modified, activated, and deactivated using &lt;code&gt;nmcli&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Check the NetworkManager status
&lt;/h2&gt;

&lt;p&gt;Start by checking the network devices:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nmcli device status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DEVICE   TYPE      STATE      CONNECTION
wlan0    wifi      connected  dex
lo       loopback  connected   lo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;wlan0&lt;/code&gt; is the Raspberry Pi's Wi-Fi interface.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;dex&lt;/code&gt; is the active Wi-Fi connection profile.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. List saved Wi-Fi profiles
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nmcli connection show
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;NAME                 UUID                                  TYPE      DEVICE
dex                  140ad8be-fcc2-475c-95af-e0491b93760a  wifi      wlan0
lo                   588680fc-bd8f-4526-9eb1-af8640764a0e  loopback  lo
MTN_4G_320E79        b9b81206-1ec4-4000-8c96-2d69716c1acd  wifi      --
Wired connection 1   13d4485f-0739-3ae3-9c21-6a8fd811361a  ethernet  --
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The important part is identifying which profile is currently connected.&lt;/p&gt;

&lt;p&gt;In my case:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;dex → wlan0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  3. Check the current IP address
&lt;/h2&gt;

&lt;p&gt;Before changing anything, record the Raspberry Pi's IP address:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;hostname&lt;/span&gt; &lt;span class="nt"&gt;-I&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;192.168.0.6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is important because after reconnecting, the router could assign the Pi a different IP address.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Scan for Wi-Fi networks
&lt;/h2&gt;

&lt;p&gt;You can scan for available networks with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nmcli device wifi list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To force a fresh scan:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nmcli device wifi rescan
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nmcli device wifi list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;NetworkManager's &lt;code&gt;nmcli device wifi&lt;/code&gt; commands can list available access points and initiate Wi-Fi connections from the command line.&lt;/p&gt;




&lt;h1&gt;
  
  
  Changing the Wi-Fi Password Remotely
&lt;/h1&gt;

&lt;p&gt;This is the important part.&lt;/p&gt;

&lt;p&gt;Suppose the Wi-Fi network is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SSID: dex
New password: NEW_PASSWORD
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Update the password stored in the Raspberry Pi's connection profile:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nmcli connection modify &lt;span class="s2"&gt;"dex"&lt;/span&gt; wifi-sec.psk &lt;span class="s2"&gt;"NEW_PASSWORD"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;wifi-sec.psk&lt;/code&gt; property represents the pre-shared key used for WPA Wi-Fi connections.&lt;/p&gt;

&lt;h3&gt;
  
  
  Important distinction
&lt;/h3&gt;

&lt;p&gt;This command &lt;strong&gt;does not change the router's actual Wi-Fi password&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It changes the password saved in the Raspberry Pi's NetworkManager connection profile.&lt;/p&gt;

&lt;p&gt;So the safe sequence is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Save the new password on the Pi.&lt;/li&gt;
&lt;li&gt;Change the actual password on the router/hotspot.&lt;/li&gt;
&lt;li&gt;Reconnect the Pi.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  5. Enable automatic reconnection
&lt;/h2&gt;

&lt;p&gt;I also recommend making sure the connection is configured to reconnect automatically:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nmcli connection modify &lt;span class="s2"&gt;"dex"&lt;/span&gt; connection.autoconnect &lt;span class="nb"&gt;yes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is particularly useful for headless devices because you don't want to manually reconnect the Pi after every reboot.&lt;/p&gt;




&lt;h2&gt;
  
  
  6. Change the actual router Wi-Fi password
&lt;/h2&gt;

&lt;p&gt;Now change the Wi-Fi password on your router/hotspot.&lt;/p&gt;

&lt;p&gt;Use &lt;strong&gt;the same password&lt;/strong&gt; that you stored in the Raspberry Pi:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Router password:
NEW_PASSWORD

Raspberry Pi saved password:
NEW_PASSWORD
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is where the headless setup becomes useful.&lt;/p&gt;

&lt;p&gt;You have already prepared the Pi for the new credentials before disconnecting it.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. Reconnect the Raspberry Pi
&lt;/h2&gt;

&lt;p&gt;After changing the router's password:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nmcli connection down &lt;span class="s2"&gt;"dex"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nmcli connection up &lt;span class="s2"&gt;"dex"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your SSH session will probably disconnect.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;That's expected.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The Pi is temporarily losing its Wi-Fi connection while it reconnects using the new credentials.&lt;/p&gt;

&lt;p&gt;NetworkManager supports explicitly activating and deactivating connection profiles with &lt;code&gt;nmcli connection up&lt;/code&gt; and &lt;code&gt;nmcli connection down&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  8. Wait and reconnect through SSH
&lt;/h2&gt;

&lt;p&gt;Give the Pi around 10–20 seconds to reconnect.&lt;/p&gt;

&lt;p&gt;Then try:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh pi@192.168.0.6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If DHCP assigned the Pi a different address, you'll need to find the new IP from your router or another device on the network.&lt;/p&gt;




&lt;h1&gt;
  
  
  Connecting the Pi to a Completely Different Wi-Fi
&lt;/h1&gt;

&lt;p&gt;If you're not changing the password of the existing network but want to connect the Pi to another Wi-Fi network, you can use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nmcli device wifi connect &lt;span class="s2"&gt;"WIFI_NAME"&lt;/span&gt; password &lt;span class="s2"&gt;"WIFI_PASSWORD"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nmcli device wifi connect &lt;span class="s2"&gt;"MyNewWiFi"&lt;/span&gt; password &lt;span class="s2"&gt;"MyNewPassword"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;NetworkManager can create and activate a connection profile when connecting to a new WPA-PSK network.&lt;/p&gt;

&lt;p&gt;You can then check the connection:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nmcli device status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And find the new IP:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;hostname&lt;/span&gt; &lt;span class="nt"&gt;-I&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Useful &lt;code&gt;nmcli&lt;/code&gt; Commands for Headless Raspberry Pi
&lt;/h1&gt;

&lt;h3&gt;
  
  
  Show network devices
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nmcli device status
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Show detailed Wi-Fi information
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nmcli device show wlan0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Show saved connections
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nmcli connection show
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Show active connections
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nmcli connection show &lt;span class="nt"&gt;--active&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Scan Wi-Fi
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nmcli device wifi list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Force Wi-Fi scan
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nmcli device wifi rescan
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Connect to Wi-Fi
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nmcli device wifi connect &lt;span class="s2"&gt;"SSID"&lt;/span&gt; password &lt;span class="s2"&gt;"PASSWORD"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Activate a saved connection
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nmcli connection up &lt;span class="s2"&gt;"CONNECTION_NAME"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Deactivate a connection
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nmcli connection down &lt;span class="s2"&gt;"CONNECTION_NAME"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Change Wi-Fi password
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nmcli connection modify &lt;span class="s2"&gt;"CONNECTION_NAME"&lt;/span&gt; wifi-sec.psk &lt;span class="s2"&gt;"NEW_PASSWORD"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Enable automatic connection
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nmcli connection modify &lt;span class="s2"&gt;"CONNECTION_NAME"&lt;/span&gt; connection.autoconnect &lt;span class="nb"&gt;yes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Find IP address
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;hostname&lt;/span&gt; &lt;span class="nt"&gt;-I&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  A Safer Trick for Remote Changes
&lt;/h1&gt;

&lt;p&gt;One particularly useful NetworkManager feature for remote administration is &lt;strong&gt;connection checkpoints&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;NetworkManager can create a temporary checkpoint before making potentially disruptive network changes. If the change isn't confirmed, the configuration can automatically be restored after the timeout.&lt;/p&gt;

&lt;p&gt;For example, NetworkManager supports:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;nmcli device checkpoint &lt;span class="nt"&gt;--timeout&lt;/span&gt; 60 &lt;span class="nt"&gt;--&lt;/span&gt; wlan0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is useful when you're making network changes over SSH and are worried about locking yourself out.&lt;/p&gt;




&lt;h1&gt;
  
  
  Final Headless Wi-Fi Workflow
&lt;/h1&gt;

&lt;p&gt;For future Raspberry Pi deployments, my basic workflow is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# 1. Identify Wi-Fi interface&lt;/span&gt;
nmcli device status

&lt;span class="c"&gt;# 2. Find active connection&lt;/span&gt;
nmcli connection show &lt;span class="nt"&gt;--active&lt;/span&gt;

&lt;span class="c"&gt;# 3. Record IP&lt;/span&gt;
&lt;span class="nb"&gt;hostname&lt;/span&gt; &lt;span class="nt"&gt;-I&lt;/span&gt;

&lt;span class="c"&gt;# 4. Update saved Wi-Fi credentials&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;nmcli connection modify &lt;span class="s2"&gt;"dex"&lt;/span&gt; wifi-sec.psk &lt;span class="s2"&gt;"NEW_PASSWORD"&lt;/span&gt;

&lt;span class="c"&gt;# 5. Enable automatic reconnection&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;nmcli connection modify &lt;span class="s2"&gt;"dex"&lt;/span&gt; connection.autoconnect &lt;span class="nb"&gt;yes&lt;/span&gt;

&lt;span class="c"&gt;# 6. Change the actual router password&lt;/span&gt;

&lt;span class="c"&gt;# 7. Reconnect Pi&lt;/span&gt;
&lt;span class="nb"&gt;sudo &lt;/span&gt;nmcli connection up &lt;span class="s2"&gt;"dex"&lt;/span&gt;

&lt;span class="c"&gt;# 8. Check connection&lt;/span&gt;
nmcli device status

&lt;span class="c"&gt;# 9. Check IP&lt;/span&gt;
&lt;span class="nb"&gt;hostname&lt;/span&gt; &lt;span class="nt"&gt;-I&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The main lesson is simple:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;When managing a headless Raspberry Pi, configure the new network credentials before breaking the existing connection.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That small precaution can save you from needing a physical keyboard and monitor just to recover Wi-Fi access.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>iot</category>
      <category>terminal</category>
      <category>cli</category>
    </item>
    <item>
      <title>How to Identify Your Raspberry Pi's RAM Size: A Developer's Guide</title>
      <dc:creator>Ikegbo Ogochukwu</dc:creator>
      <pubDate>Thu, 23 Jul 2026 13:33:20 +0000</pubDate>
      <link>https://dev.to/kenryikegbo/how-to-identify-your-raspberry-pis-ram-size-a-developers-guide-4l5c</link>
      <guid>https://dev.to/kenryikegbo/how-to-identify-your-raspberry-pis-ram-size-a-developers-guide-4l5c</guid>
      <description>&lt;p&gt;Ever inherited a Raspberry Pi board, bought a used one, or forgot which model you grabbed from your electronics drawer? Since many Pi boards share the exact same physical layout, telling a 2GB, 4GB, or 8GB model apart just by looking at the green PCB can be tricky.&lt;/p&gt;

&lt;h2&gt;
  
  
  Here are the four best ways to identify your Raspberry Pi’s RAM size, ranging from quick terminal commands to inspecting the hardware components.
&lt;/h2&gt;

&lt;h2&gt;
  
  
  1. The Software Way: Terminal Commands (Fastest)
&lt;/h2&gt;

&lt;p&gt;If your Raspberry Pi is powered on and you can access the terminal (via SSH or a desktop window), software commands provide the quickest answer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Method A: Check /proc/meminfo
&lt;/h2&gt;

&lt;p&gt;The Linux kernel keeps track of system memory in the /proc virtual filesystem. Run this command to see your total memory in kilobytes:&lt;/p&gt;

&lt;p&gt;cat /proc/meminfo | grep MemTotal&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What to look for:&lt;/li&gt;
&lt;li&gt;~940,000 kB = 1GB

&lt;ul&gt;
&lt;li&gt;~1,900,000 kB = 2GB&lt;/li&gt;
&lt;li&gt;~3,800,000 kB = 4GB&lt;/li&gt;
&lt;li&gt;~7,800,000 kB = 8GB&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Method B: Use the free Command
&lt;/h2&gt;

&lt;p&gt;For a more human-readable format, use the free tool with the -h (human-readable) flag:&lt;/p&gt;

&lt;p&gt;free -h&lt;/p&gt;

&lt;h2&gt;
  
  
  Look under the Total column in the Mem row. It will explicitly display 1.8Gi, 3.7Gi, or 7.6Gi.
&lt;/h2&gt;

&lt;h2&gt;
  
  
  2. The Configuration Way: Reading the Revision Code
&lt;/h2&gt;

&lt;p&gt;Every Raspberry Pi has a specific hardware revision code embedded in its processor. This code encodes the model, revision number, manufacturer, and exact RAM size.&lt;br&gt;
Run this command:&lt;/p&gt;

&lt;p&gt;cat /proc/cpuinfo | grep Revision&lt;/p&gt;

&lt;p&gt;You will get a 4-to-6-digit hexadecimal string (e.g., c03111 or d03114). You can match your code against the official Raspberry Pi documentation, or use this quick cheat sheet for the Raspberry Pi 4 Model B:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;b03111 / b03112 / b03114 / b03115 = 2GB RAM&lt;/li&gt;
&lt;li&gt;c03111 / c03112 / c03114 / c03115 = 4GB RAM&lt;/li&gt;
&lt;li&gt;d03114 / d03115 = 8GB RAM&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  3. The Visual Way: Reading Silk-Screened PCB Markings
&lt;/h2&gt;

&lt;p&gt;If your Pi is powered off, look directly at the top of the circuit board.&lt;/p&gt;

&lt;h2&gt;
  
  
  Raspberry Pi 5 and Recent Pi 4 Boards
&lt;/h2&gt;

&lt;p&gt;On newer Raspberry Pi models, the developers made our lives incredibly easy. Look closely at the top-right corner of the board, right next to the headphone jack or micro-HDMI ports. You will see small, silver silk-screened text directly on the board indicating the memory size:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;2, 4, or 8 printed explicitly inside a small rectangular border.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Older Pi 4 Boards
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Look closely at the board between the USB ports and the 40-pin GPIO header. The text Raspberry Pi 4 Model B is printed there. On some production runs, the RAM size is printed directly after the model name.
&lt;/h2&gt;

&lt;h2&gt;
  
  
  4. The Hardware Way: Decoding the RAM Chip FBGA Code
&lt;/h2&gt;

&lt;p&gt;If your board doesn't have the size printed on the PCB, you can read the physical markings on the RAM chip itself. The RAM is the square, dark-metallic integrated circuit (IC) located right next to the main Broadcom CPU.&lt;br&gt;
Raspberry Pi uses memory chips from manufacturers like Micron or Samsung. Micron chips use a 5-digit alphanumeric FBGA code instead of a traditional part number.&lt;br&gt;
You can look up the code on Micron's website, or reference these common Raspberry Pi 4/5 markers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;D9WHV = 2GB LPDDR4&lt;/li&gt;
&lt;li&gt;D9WHZ = 4GB LPDDR4&lt;/li&gt;
&lt;li&gt;D9ZCL = 8GB LPDDR4X&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Summary: Which Method Should You Use?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Pi is running headless? Use free -h.&lt;/li&gt;
&lt;li&gt;Writing an automation script? Parse /proc/cpuinfo for the revision code.&lt;/li&gt;
&lt;li&gt;Pi is sitting on your desk unplugged? Check the silver silk-screened number on the corner of the PCB.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;How do you usually check your Pi hardware specs? Let me know in the comments below!&lt;/p&gt;

</description>
      <category>micropython</category>
      <category>raspberrypi</category>
      <category>iot</category>
      <category>mojo</category>
    </item>
    <item>
      <title>Understanding ADCs and Using the ADS1115 with Raspberry Pi</title>
      <dc:creator>Ikegbo Ogochukwu</dc:creator>
      <pubDate>Tue, 16 Jun 2026 11:35:42 +0000</pubDate>
      <link>https://dev.to/kenryikegbo/understanding-adcs-and-using-the-ads1115-with-raspberry-pi-40m6</link>
      <guid>https://dev.to/kenryikegbo/understanding-adcs-and-using-the-ads1115-with-raspberry-pi-40m6</guid>
      <description>&lt;h1&gt;
  
  
  Understanding ADCs and Using the ADS1115 with Raspberry Pi
&lt;/h1&gt;

&lt;p&gt;&lt;em&gt;Learn how analog signals become digital data, and how to connect the ADS1115 ADC to a Raspberry Pi for high-precision sensor measurements.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;One of the first surprises many Raspberry Pi users encounter is that the Pi has &lt;strong&gt;no built-in Analog-to-Digital Converter (ADC)&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This means that while the Raspberry Pi excels at digital communication, it cannot directly read analog sensors such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Potentiometers&lt;/li&gt;
&lt;li&gt;Light sensors (LDRs)&lt;/li&gt;
&lt;li&gt;Gas sensors&lt;/li&gt;
&lt;li&gt;Analog temperature sensors&lt;/li&gt;
&lt;li&gt;Soil moisture sensors&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To bridge this gap, we use an external ADC such as the &lt;strong&gt;ADS1115&lt;/strong&gt;, a high-precision 16-bit ADC that communicates with the Raspberry Pi over I²C. The ADS1115 provides four analog input channels, programmable gain amplification, and up to 860 samples per second. (&lt;a href="https://www.ti.com/product/ADS1115?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Texas Instruments&lt;/a&gt;)&lt;/p&gt;




&lt;h2&gt;
  
  
  What is an ADC?
&lt;/h2&gt;

&lt;p&gt;An &lt;strong&gt;Analog-to-Digital Converter (ADC)&lt;/strong&gt; converts a continuously varying analog voltage into a digital number that software can process.&lt;/p&gt;

&lt;p&gt;Consider a potentiometer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Potentiometer
     │
     ▼
  0V ───────► 3.3V
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output voltage changes smoothly as you rotate the knob.&lt;/p&gt;

&lt;p&gt;A computer, however, understands only numbers.&lt;/p&gt;

&lt;p&gt;The ADC measures the voltage and converts it into a digital value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Analog Voltage
      │
      ▼
+------------+
|    ADC     |
+------------+
      │
      ▼
Digital Value
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The Principle Behind ADCs
&lt;/h2&gt;

&lt;p&gt;ADC conversion involves three major stages.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Sampling
&lt;/h3&gt;

&lt;p&gt;The ADC captures the voltage at a specific moment in time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Voltage

5V |      /\
   |     /  \
   |    /    \
0V +---+------+----&amp;gt; Time
      ↑
   Sample
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The sampled voltage is then processed.&lt;/p&gt;




&lt;h3&gt;
  
  
  2. Quantization
&lt;/h3&gt;

&lt;p&gt;The ADC divides the voltage range into discrete levels.&lt;/p&gt;

&lt;p&gt;For example, a 3-bit ADC can represent:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2³ = 8 levels
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0V ───────────── 8V
│ │ │ │ │ │ │ │
0 1 2 3 4 5 6 7
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Any input voltage is rounded to the nearest level.&lt;/p&gt;




&lt;h3&gt;
  
  
  3. Encoding
&lt;/h3&gt;

&lt;p&gt;The selected level is represented in binary form.&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Voltage&lt;/th&gt;
&lt;th&gt;Level&lt;/th&gt;
&lt;th&gt;Binary&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;5.3V&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;101&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The ADC outputs the binary value to the processor.&lt;/p&gt;




&lt;h2&gt;
  
  
  ADC Resolution Explained
&lt;/h2&gt;

&lt;p&gt;Resolution determines how many unique values an ADC can produce.&lt;/p&gt;

&lt;p&gt;Formula:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Levels = 2^N
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;where &lt;strong&gt;N&lt;/strong&gt; is the number of bits.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Resolution&lt;/th&gt;
&lt;th&gt;Levels&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;8-bit&lt;/td&gt;
&lt;td&gt;256&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10-bit&lt;/td&gt;
&lt;td&gt;1,024&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;12-bit&lt;/td&gt;
&lt;td&gt;4,096&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;16-bit&lt;/td&gt;
&lt;td&gt;65,536&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Higher resolution means greater measurement precision.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why the ADS1115 is Popular
&lt;/h2&gt;

&lt;p&gt;The ADS1115 is a 16-bit delta-sigma ADC featuring:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;16-bit resolution&lt;/li&gt;
&lt;li&gt;Four analog input channels&lt;/li&gt;
&lt;li&gt;I²C communication&lt;/li&gt;
&lt;li&gt;Programmable Gain Amplifier (PGA)&lt;/li&gt;
&lt;li&gt;Differential measurements&lt;/li&gt;
&lt;li&gt;Up to 860 samples/sec&lt;/li&gt;
&lt;li&gt;Supply voltage from 2.0V to 5.5V (&lt;a href="https://www.ti.com/product/ADS1115?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Texas Instruments&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  ADS1115 Module
&lt;/h3&gt;




&lt;h2&gt;
  
  
  Why Raspberry Pi Needs the ADS1115
&lt;/h2&gt;

&lt;p&gt;Unlike many microcontrollers, the Raspberry Pi does not include ADC hardware.&lt;/p&gt;

&lt;p&gt;Without an ADC:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# This will not work on Raspberry Pi
&lt;/span&gt;&lt;span class="nf"&gt;analogRead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sensor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the ADS1115:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Sensor
  │
  ▼
ADS1115
  │
  ▼
I²C Bus
  │
  ▼
Raspberry Pi
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Pi reads digital values from the ADS1115 through I²C. (&lt;a href="https://learn.adafruit.com/raspberry-pi-analog-to-digital-converters/ads1015-slash-ads1115?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Adafruit Learning System&lt;/a&gt;)&lt;/p&gt;




&lt;h1&gt;
  
  
  Hardware Connections
&lt;/h1&gt;

&lt;p&gt;Connect the ADS1115 to the Raspberry Pi as follows:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;ADS1115&lt;/th&gt;
&lt;th&gt;Raspberry Pi&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;VDD&lt;/td&gt;
&lt;td&gt;3.3V&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GND&lt;/td&gt;
&lt;td&gt;GND&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SDA&lt;/td&gt;
&lt;td&gt;GPIO2 (SDA)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SCL&lt;/td&gt;
&lt;td&gt;GPIO3 (SCL)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Wiring Diagram
&lt;/h3&gt;




&lt;h1&gt;
  
  
  Enable I²C on Raspberry Pi
&lt;/h1&gt;

&lt;p&gt;Open Raspberry Pi configuration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;raspi-config
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Navigate to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Interface Options
 └── I2C
     └── Enable
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Reboot:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;reboot
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify the ADS1115 is detected:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; i2c-tools

i2cdetect &lt;span class="nt"&gt;-y&lt;/span&gt; 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Expected output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;48
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The default I²C address of the ADS1115 is &lt;strong&gt;0x48&lt;/strong&gt;. (&lt;a href="https://www.instructables.com/How-to-Use-ADS1115-With-the-Raspberry-Pi-Part-1/?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Instructables&lt;/a&gt;)&lt;/p&gt;




&lt;h1&gt;
  
  
  Installing Python Libraries
&lt;/h1&gt;

&lt;p&gt;Install the required packages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update

pip &lt;span class="nb"&gt;install &lt;/span&gt;adafruit-circuitpython-ads1x15
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Adafruit ADS1x15 library provides Python support for both ADS1015 and ADS1115 devices. (&lt;a href="https://docs.circuitpython.org/projects/ads1x15/en/latest/?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;CircuitPython Docs&lt;/a&gt;)&lt;/p&gt;




&lt;h1&gt;
  
  
  Reading Analog Voltages
&lt;/h1&gt;

&lt;p&gt;Create a file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nano ads1115_test.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Paste:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;board&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;busio&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;adafruit_ads1x15.ads1115&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;ADS&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;adafruit_ads1x15.analog_in&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AnalogIn&lt;/span&gt;

&lt;span class="n"&gt;i2c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;busio&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;I2C&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;board&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SCL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;board&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SDA&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;ads&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ADS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ADS1115&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i2c&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;chan&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;AnalogIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ads&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ADS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;P0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&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;Voltage: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;chan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;voltage&lt;/span&gt;&lt;span class="si"&gt;:&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;V&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;p&gt;Run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python ads1115_test.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Voltage: 1.245V
Voltage: 1.251V
Voltage: 1.260V
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Reading a Potentiometer
&lt;/h1&gt;

&lt;p&gt;Connect:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;3.3V ─────┐
          │
      Potentiometer
          │
A0 ◄──────┘
          │
GND ──────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;adafruit_ads1x15.analog_in&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;AnalogIn&lt;/span&gt;

&lt;span class="n"&gt;pot&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;AnalogIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ads&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ADS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;P0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="bp"&gt;True&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="n"&gt;pot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see values changing as the knob rotates.&lt;/p&gt;




&lt;h1&gt;
  
  
  Measuring Multiple Sensors
&lt;/h1&gt;

&lt;p&gt;The ADS1115 provides four channels:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;A0
A1
A2
A3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;ch0&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;AnalogIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ads&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ADS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;P0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;ch1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;AnalogIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ads&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ADS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;P1&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="n"&gt;ch0&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;voltage&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="n"&gt;ch1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;voltage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This allows one Raspberry Pi to monitor multiple analog sensors simultaneously.&lt;/p&gt;




&lt;h1&gt;
  
  
  Differential Measurements
&lt;/h1&gt;

&lt;p&gt;The ADS1115 can measure the difference between two voltages.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;diff&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;AnalogIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ads&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ADS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;P0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ADS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;P1&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="n"&gt;diff&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;voltage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Useful for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Current sensing&lt;/li&gt;
&lt;li&gt;Wheatstone bridges&lt;/li&gt;
&lt;li&gt;Precision instrumentation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The ADS1115 supports both single-ended and differential input configurations. (&lt;a href="https://www.adafruit.com/product/1085?srsltid=AfmBOornd2pV-qzUkaXlpEAtu4lODVBFaulyydlca6kqQF62uVfCtaPU&amp;amp;utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Adafruit&lt;/a&gt;)&lt;/p&gt;




&lt;h1&gt;
  
  
  Understanding the Programmable Gain Amplifier (PGA)
&lt;/h1&gt;

&lt;p&gt;One of the most powerful ADS1115 features is its built-in PGA.&lt;/p&gt;

&lt;p&gt;Suppose your sensor outputs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0V - 0.2V
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using the PGA:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;ads&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gain&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The signal is amplified internally, allowing much higher measurement precision. (&lt;a href="https://learn.adafruit.com/raspberry-pi-analog-to-digital-converters/ads1015-slash-ads1115?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Adafruit Learning System&lt;/a&gt;)&lt;/p&gt;




&lt;h1&gt;
  
  
  Real-World Applications
&lt;/h1&gt;

&lt;p&gt;The ADS1115 is commonly used in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Smart agriculture&lt;/li&gt;
&lt;li&gt;Environmental monitoring&lt;/li&gt;
&lt;li&gt;Battery management systems&lt;/li&gt;
&lt;li&gt;Industrial automation&lt;/li&gt;
&lt;li&gt;Embedded AI projects&lt;/li&gt;
&lt;li&gt;Raspberry Pi sensor networks&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example workflow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Temperature Sensor
       │
       ▼
    ADS1115
       │
       ▼
 Raspberry Pi
       │
       ▼
 Machine Learning Model
       │
       ▼
 Prediction
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Common Troubleshooting
&lt;/h1&gt;

&lt;h3&gt;
  
  
  Device Not Found
&lt;/h3&gt;

&lt;p&gt;Check wiring:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;i2cdetect &lt;span class="nt"&gt;-y&lt;/span&gt; 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;0x48&lt;/code&gt; is missing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Verify SDA connection&lt;/li&gt;
&lt;li&gt;Verify SCL connection&lt;/li&gt;
&lt;li&gt;Verify power supply&lt;/li&gt;
&lt;/ul&gt;




&lt;h3&gt;
  
  
  Permission Errors
&lt;/h3&gt;

&lt;p&gt;Add your user to the required groups:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;usermod &lt;span class="nt"&gt;-aG&lt;/span&gt; gpio,i2c &lt;span class="nv"&gt;$USER&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Logout and login again.&lt;/p&gt;




&lt;h3&gt;
  
  
  Incorrect Voltage Readings
&lt;/h3&gt;

&lt;p&gt;Verify:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Sensor voltage range&lt;/li&gt;
&lt;li&gt;ADS1115 gain setting&lt;/li&gt;
&lt;li&gt;Ground connections&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Final Thoughts
&lt;/h1&gt;

&lt;p&gt;The ADS1115 is one of the most useful expansion modules for Raspberry Pi projects. It solves the Pi's lack of analog inputs while providing significantly higher precision than many built-in microcontroller ADCs.&lt;/p&gt;

&lt;p&gt;By understanding how ADCs work—through &lt;strong&gt;sampling&lt;/strong&gt;, &lt;strong&gt;quantization&lt;/strong&gt;, and &lt;strong&gt;encoding&lt;/strong&gt;—you gain a deeper appreciation of how physical sensor data becomes digital information that software, machine learning models, and intelligent systems can use.&lt;/p&gt;

&lt;p&gt;If you're building IoT devices, sensor networks, robotics systems, or Embedded AI projects, the ADS1115 is an excellent addition to your toolkit.&lt;/p&gt;




&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.ti.com/product/ADS1115?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Texas Instruments ADS1115 Datasheet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.circuitpython.org/projects/ads1x15/en/latest/?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Adafruit ADS1x15 Python Library Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.adafruit.com/raspberry-pi-analog-to-digital-converters/ads1015-slash-ads1115?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Adafruit Raspberry Pi ADC Guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Happy building!&lt;/em&gt; 🚀&lt;/p&gt;

</description>
      <category>ai</category>
      <category>iot</category>
      <category>raspberrypi</category>
      <category>adc</category>
    </item>
    <item>
      <title>How to Fix SSH Error: "REMOTE HOST IDENTIFICATION HAS CHANGED!"</title>
      <dc:creator>Ikegbo Ogochukwu</dc:creator>
      <pubDate>Tue, 02 Jun 2026 10:55:55 +0000</pubDate>
      <link>https://dev.to/kenryikegbo/how-to-fix-ssh-error-remote-host-identification-has-changed-4i97</link>
      <guid>https://dev.to/kenryikegbo/how-to-fix-ssh-error-remote-host-identification-has-changed-4i97</guid>
      <description>&lt;p&gt;&lt;strong&gt;A quick, step-by-step guide to resolving the dreaded SSH host key verification failure when connecting to your Raspberry Pi or remote server.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We have all been there. You flash a fresh OS onto your Raspberry Pi, try to SSH back into it using the same hostname, and boom—your terminal screens at you with a massive wall of warning text:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@    WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!     @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
...
Host key verification failed.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Why is this happening?
&lt;/h3&gt;

&lt;p&gt;Your computer keeps a local registry of unique security keys (fingerprints) for every server you connect to inside a file named &lt;code&gt;known_hosts&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;When you reinstall an OS or change your remote device, its security key changes. Your computer notices that the new key doesn't match the old saved key, panics, and blocks the connection to protect you from a potential Man-in-the-Middle (MITM) attack. &lt;/p&gt;

&lt;p&gt;Since you know &lt;em&gt;you&lt;/em&gt; caused this change, it is safe to bypass. Here are the two quickest ways to fix it on Windows.&lt;/p&gt;




&lt;h3&gt;
  
  
  Solution 1: The One-Line Terminal Fix (Recommended) 🚀
&lt;/h3&gt;

&lt;p&gt;The fastest approach is to let the system automatically remove the old, conflicting key. Open your Command Prompt or PowerShell and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh-keygen &lt;span class="nt"&gt;-R&lt;/span&gt; raspberrypi.local
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;(Replace &lt;code&gt;raspberrypi.local&lt;/code&gt; with your target IP address if you are connecting via IP).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What this does:&lt;/strong&gt; It searches your local &lt;code&gt;known_hosts&lt;/code&gt; file, strips out the outdated entry, and saves a backup of your old file just in case.&lt;/p&gt;




&lt;h3&gt;
  
  
  Solution 2: Manual Line Surgery 🛠️
&lt;/h3&gt;

&lt;p&gt;If the automated command fails or you prefer to see exactly what you are deleting, you can edit the file directly using Notepad.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Press &lt;code&gt;Win + R&lt;/code&gt; to open the Run window.&lt;/li&gt;
&lt;li&gt;Paste the following path and click &lt;strong&gt;OK&lt;/strong&gt;:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   notepad C:\Users\PAVILION\.ssh\known_hosts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Look at your original error message. It will tell you exactly which line is broken (e.g., &lt;code&gt;offending ECDSA key in ...known_hosts:6&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Go to &lt;strong&gt;Line 6&lt;/strong&gt; in Notepad, delete that entire line, delete any blank spaces, and save (&lt;code&gt;Ctrl + S&lt;/code&gt;).&lt;/li&gt;
&lt;/ol&gt;




&lt;h3&gt;
  
  
  Connecting Again
&lt;/h3&gt;

&lt;p&gt;Once the old key is cleared out, try connecting to your Raspberry Pi again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh pi@raspberrypi.local
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your terminal will now ask if you want to trust the new fingerprint. Type &lt;strong&gt;&lt;code&gt;yes&lt;/code&gt;&lt;/strong&gt;, press &lt;strong&gt;Enter&lt;/strong&gt;, and you are officially back in business!&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Found this helpful? Drop a unicorn 🦄 or bookmark it for the next time you rebuild your homelab!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>ssh</category>
      <category>raspberrypi</category>
      <category>windows</category>
      <category>devops</category>
    </item>
    <item>
      <title>Stop Guessing Your Network: Using PowerShell and TCP Commands to Understand What’s Happening Behind the Scenes</title>
      <dc:creator>Ikegbo Ogochukwu</dc:creator>
      <pubDate>Tue, 19 May 2026 18:47:05 +0000</pubDate>
      <link>https://dev.to/kenryikegbo/stop-guessing-your-network-using-powershell-and-tcp-commands-to-understand-whats-happening-behind-51mf</link>
      <guid>https://dev.to/kenryikegbo/stop-guessing-your-network-using-powershell-and-tcp-commands-to-understand-whats-happening-behind-51mf</guid>
      <description>&lt;p&gt;Most developers and IT beginners only touch networking when something breaks.&lt;/p&gt;

&lt;p&gt;The internet is “working,” the API is responding, Docker containers are starting, and life moves on.&lt;/p&gt;

&lt;p&gt;Until one day:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your app cannot connect to a database&lt;/li&gt;
&lt;li&gt;Docker says the daemon is unreachable&lt;/li&gt;
&lt;li&gt;A server responds slowly for no obvious reason&lt;/li&gt;
&lt;li&gt;A device disappears from the network&lt;/li&gt;
&lt;li&gt;SSH refuses connections&lt;/li&gt;
&lt;li&gt;Your Raspberry Pi suddenly becomes invisible&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is usually when people realize they do not actually understand their network.&lt;/p&gt;

&lt;p&gt;One of the best ways to fix that is by learning how to inspect and troubleshoot networks directly from the terminal using PowerShell and TCP-based tools.&lt;/p&gt;

&lt;p&gt;This post is inspired by a networking article from &lt;a href="https://blog.paessler.com/know-your-network-with-powershell-and-tcp?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Paessler Blog&lt;/a&gt; and expands it into a more developer-focused practical guide. (&lt;a href="https://blog.paessler.com/know-your-network-with-powershell-and-tcp?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;blog.paessler.com&lt;/a&gt;)&lt;/p&gt;




&lt;h1&gt;
  
  
  Why PowerShell Matters for Networking
&lt;/h1&gt;

&lt;p&gt;For years, networking on Windows relied heavily on old tools like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ping&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ipconfig&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;netstat&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tracert&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;netsh&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These still work.&lt;/p&gt;

&lt;p&gt;But modern Windows networking is increasingly PowerShell-driven. Microsoft has gradually shifted many administration and diagnostic workflows toward PowerShell because it is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;scriptable&lt;/li&gt;
&lt;li&gt;automatable&lt;/li&gt;
&lt;li&gt;object-oriented&lt;/li&gt;
&lt;li&gt;easier to integrate into larger workflows&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of parsing messy text output, PowerShell returns structured objects you can filter, sort, and automate. (&lt;a href="https://blog.paessler.com/know-your-network-with-powershell-and-tcp?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;blog.paessler.com&lt;/a&gt;)&lt;/p&gt;




&lt;h1&gt;
  
  
  Understanding TCP Before Troubleshooting
&lt;/h1&gt;

&lt;p&gt;Most developer tools rely on TCP underneath:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Docker&lt;/li&gt;
&lt;li&gt;APIs&lt;/li&gt;
&lt;li&gt;databases&lt;/li&gt;
&lt;li&gt;SSH&lt;/li&gt;
&lt;li&gt;web servers&lt;/li&gt;
&lt;li&gt;cloud platforms&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;TCP (Transmission Control Protocol) is responsible for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;reliable communication&lt;/li&gt;
&lt;li&gt;packet ordering&lt;/li&gt;
&lt;li&gt;retransmission&lt;/li&gt;
&lt;li&gt;connection establishment&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When applications fail to communicate, the problem is often not the application itself — it is the TCP/network layer.&lt;/p&gt;

&lt;p&gt;Understanding a few networking commands can save hours of frustration.&lt;/p&gt;




&lt;h1&gt;
  
  
  1. Check Your Network Configuration
&lt;/h1&gt;

&lt;p&gt;The first thing to inspect is your machine’s network configuration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Get-NetIPAddress&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This gives you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;IP address&lt;/li&gt;
&lt;li&gt;subnet&lt;/li&gt;
&lt;li&gt;interface&lt;/li&gt;
&lt;li&gt;IPv4/IPv6 details&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can also use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;ipconfig&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But PowerShell gives more structured information.&lt;/p&gt;




&lt;h1&gt;
  
  
  2. Test Connectivity Properly
&lt;/h1&gt;

&lt;p&gt;Most people know &lt;code&gt;ping&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;PowerShell modernizes it with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Test-Connection&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;google.com&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can test multiple systems:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Test-Connection&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;google.com&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;github.com&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or continuously monitor latency:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Test-Connection&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;192.168.1.1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;10&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This helps detect:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;unstable Wi-Fi&lt;/li&gt;
&lt;li&gt;packet loss&lt;/li&gt;
&lt;li&gt;intermittent routing issues&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Microsoft’s networking documentation also recommends PowerShell-based connectivity testing for modern administration workflows. (&lt;a href="https://learn.microsoft.com/en-us/powershell/scripting/samples/performing-networking-tasks?view=powershell-7.6&amp;amp;utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Microsoft Learn&lt;/a&gt;)&lt;/p&gt;




&lt;h1&gt;
  
  
  3. Discover Devices on Your Network
&lt;/h1&gt;

&lt;p&gt;One of the most useful troubleshooting techniques is identifying what devices are actually online.&lt;/p&gt;

&lt;p&gt;You can inspect your ARP table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;arp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-a&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This maps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;IP addresses&lt;/li&gt;
&lt;li&gt;MAC addresses&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;to devices your machine has communicated with recently.&lt;/p&gt;

&lt;p&gt;Modern network discovery guides still rely heavily on ARP-based discovery for local troubleshooting. (&lt;a href="https://blog.paessler.com/network-device-lists-and-discovery?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;blog.paessler.com&lt;/a&gt;)&lt;/p&gt;




&lt;h1&gt;
  
  
  4. Scan an Entire Subnet
&lt;/h1&gt;

&lt;p&gt;Suppose your Raspberry Pi disappeared from the network.&lt;/p&gt;

&lt;p&gt;You can sweep your subnet:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;254&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ForEach-Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;Test-Connection&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"192.168.1.&lt;/span&gt;&lt;span class="bp"&gt;$_&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Quiet&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This checks which devices respond.&lt;/p&gt;

&lt;p&gt;Microsoft demonstrates similar subnet enumeration approaches in PowerShell networking examples. (&lt;a href="https://learn.microsoft.com/en-us/powershell/scripting/samples/performing-networking-tasks?view=powershell-7.6&amp;amp;utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Microsoft Learn&lt;/a&gt;)&lt;/p&gt;




&lt;h1&gt;
  
  
  5. Find Open TCP Ports
&lt;/h1&gt;

&lt;p&gt;Sometimes the device is online, but the service is not.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;SSH may not be running&lt;/li&gt;
&lt;li&gt;Docker daemon may be down&lt;/li&gt;
&lt;li&gt;database service may have crashed&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can test ports directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Test-NetConnection&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;192.168.1.10&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Port&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;22&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example ports:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Service&lt;/th&gt;
&lt;th&gt;Port&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SSH&lt;/td&gt;
&lt;td&gt;22&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HTTP&lt;/td&gt;
&lt;td&gt;80&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HTTPS&lt;/td&gt;
&lt;td&gt;443&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MySQL&lt;/td&gt;
&lt;td&gt;3306&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PostgreSQL&lt;/td&gt;
&lt;td&gt;5432&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Docker API&lt;/td&gt;
&lt;td&gt;2375/2376&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This immediately tells you whether the issue is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;routing&lt;/li&gt;
&lt;li&gt;firewall&lt;/li&gt;
&lt;li&gt;service availability&lt;/li&gt;
&lt;li&gt;TCP-level rejection&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  6. Monitor Active TCP Connections
&lt;/h1&gt;

&lt;p&gt;To inspect live connections:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Get-NetTCPConnection&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can filter by state:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Get-NetTCPConnection&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Where-Object&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="bp"&gt;$_&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;State&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-eq&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Established"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or inspect a specific port:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Get-NetTCPConnection&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-LocalPort&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;80&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is extremely useful when debugging:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;APIs&lt;/li&gt;
&lt;li&gt;containers&lt;/li&gt;
&lt;li&gt;backend services&lt;/li&gt;
&lt;li&gt;reverse proxies&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  7. Troubleshoot Docker Connectivity
&lt;/h1&gt;

&lt;p&gt;If Docker suddenly breaks on Windows, PowerShell networking commands become incredibly useful.&lt;/p&gt;

&lt;p&gt;For example, errors like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;failed to connect to the docker API
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;often indicate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Docker daemon stopped&lt;/li&gt;
&lt;li&gt;named pipe failure&lt;/li&gt;
&lt;li&gt;TCP bridge issue&lt;/li&gt;
&lt;li&gt;virtualization problem&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Useful checks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Get-Service&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;docker&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Test-NetConnection&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;localhost&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Port&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;2375&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;docker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ls&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Understanding networking basics makes Docker troubleshooting much easier because Docker heavily relies on virtual networking and TCP communication internally.&lt;/p&gt;




&lt;h1&gt;
  
  
  8. Automate Network Diagnostics
&lt;/h1&gt;

&lt;p&gt;This is where PowerShell becomes powerful.&lt;/p&gt;

&lt;p&gt;Instead of manually checking systems one by one, you can automate diagnostics.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="nv"&gt;$servers&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;@(&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"192.168.1.10"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"192.168.1.11"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"192.168.1.12"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="kr"&gt;foreach&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$server&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kr"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$servers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="n"&gt;Test-NetConnection&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$server&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Port&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;22&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can verify SSH availability across multiple systems automatically.&lt;/p&gt;

&lt;p&gt;This scales extremely well for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;labs&lt;/li&gt;
&lt;li&gt;classrooms&lt;/li&gt;
&lt;li&gt;hubs&lt;/li&gt;
&lt;li&gt;server farms&lt;/li&gt;
&lt;li&gt;IoT deployments&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  9. Network Monitoring at Scale
&lt;/h1&gt;

&lt;p&gt;At some point, command-line troubleshooting is not enough.&lt;/p&gt;

&lt;p&gt;That is where monitoring systems come in.&lt;/p&gt;

&lt;p&gt;Platforms like &lt;a href="https://www.paessler.com/prtg?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;PRTG Network Monitor&lt;/a&gt; automate:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;network discovery&lt;/li&gt;
&lt;li&gt;latency tracking&lt;/li&gt;
&lt;li&gt;device monitoring&lt;/li&gt;
&lt;li&gt;traffic inspection&lt;/li&gt;
&lt;li&gt;uptime monitoring&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Modern network visibility systems combine:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ARP discovery&lt;/li&gt;
&lt;li&gt;TCP monitoring&lt;/li&gt;
&lt;li&gt;SNMP&lt;/li&gt;
&lt;li&gt;device inventories&lt;/li&gt;
&lt;li&gt;automated alerting&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;to give administrators full infrastructure visibility. (&lt;a href="https://blog.paessler.com/network-device-lists-and-discovery?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;blog.paessler.com&lt;/a&gt;)&lt;/p&gt;




&lt;h1&gt;
  
  
  Real Lesson: Developers Need Networking Skills
&lt;/h1&gt;

&lt;p&gt;One pattern keeps repeating in modern software engineering:&lt;/p&gt;

&lt;p&gt;The deeper you go, the more networking matters.&lt;/p&gt;

&lt;p&gt;Machine learning engineers, backend developers, DevOps engineers, cybersecurity analysts, embedded engineers, and cloud architects all eventually run into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ports&lt;/li&gt;
&lt;li&gt;sockets&lt;/li&gt;
&lt;li&gt;firewalls&lt;/li&gt;
&lt;li&gt;routing&lt;/li&gt;
&lt;li&gt;DNS&lt;/li&gt;
&lt;li&gt;TCP failures&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Networking knowledge is no longer optional.&lt;/p&gt;




&lt;h1&gt;
  
  
  Final Thoughts
&lt;/h1&gt;

&lt;p&gt;Learning PowerShell networking commands is not about becoming a network engineer overnight.&lt;/p&gt;

&lt;p&gt;It is about gaining visibility.&lt;/p&gt;

&lt;p&gt;Once you can inspect:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;connections&lt;/li&gt;
&lt;li&gt;devices&lt;/li&gt;
&lt;li&gt;ports&lt;/li&gt;
&lt;li&gt;adapters&lt;/li&gt;
&lt;li&gt;latency&lt;/li&gt;
&lt;li&gt;routing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;you stop guessing and start diagnosing systems properly.&lt;/p&gt;

&lt;p&gt;And honestly, that is one of the biggest transitions from beginner developer to advanced engineer.&lt;/p&gt;




&lt;h1&gt;
  
  
  Further Reading
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog.paessler.com/know-your-network-with-powershell-and-tcp?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Paessler Networking Article&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/en-us/powershell/scripting/samples/performing-networking-tasks?view=powershell-7.6&amp;amp;utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Microsoft PowerShell Networking Tasks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.techtarget.com/searchnetworking/tip/PowerShell-commands-for-network-troubleshooting?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;PowerShell Network Troubleshooting Guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;(&lt;a href="https://blog.paessler.com/know-your-network-with-powershell-and-tcp?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;blog.paessler.com&lt;/a&gt;)&lt;/p&gt;

</description>
      <category>cli</category>
      <category>networking</category>
      <category>webdev</category>
      <category>docker</category>
    </item>
    <item>
      <title>From Zero to Supercomputing: A Beginner-Friendly Guide to Using HPC Clusters Like CINECA</title>
      <dc:creator>Ikegbo Ogochukwu</dc:creator>
      <pubDate>Thu, 14 May 2026 11:05:39 +0000</pubDate>
      <link>https://dev.to/kenryikegbo/-from-zero-to-supercomputing-a-beginner-friendly-guide-to-using-hpc-clusters-like-cineca-55jm</link>
      <guid>https://dev.to/kenryikegbo/-from-zero-to-supercomputing-a-beginner-friendly-guide-to-using-hpc-clusters-like-cineca-55jm</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;A practical introduction to Linux, SLURM, GPU clusters, AI workloads, and supercomputing workflows.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Supercomputers are no longer reserved only for physicists and national laboratories.&lt;/p&gt;

&lt;p&gt;Today, AI engineers, machine learning researchers, data scientists, and students increasingly rely on High Performance Computing (HPC) systems for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;large-scale AI training&lt;/li&gt;
&lt;li&gt;scientific simulations&lt;/li&gt;
&lt;li&gt;big data analytics&lt;/li&gt;
&lt;li&gt;distributed computing&lt;/li&gt;
&lt;li&gt;computational research&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Recently, I started exploring the documentation of the CINECA HPC infrastructure, one of Europe’s major supercomputing environments, and I realized something important:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Most beginners struggle not because HPC is impossible, but because the ecosystem feels overwhelming at first.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This article breaks down the core concepts into a practical workflow that beginners can actually understand.&lt;/p&gt;




&lt;h1&gt;
  
  
  What Is an HPC Cluster?
&lt;/h1&gt;

&lt;p&gt;An HPC (High Performance Computing) cluster is a network of powerful computers called &lt;strong&gt;nodes&lt;/strong&gt; working together to solve computational problems.&lt;/p&gt;

&lt;p&gt;Instead of training a model on:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;one laptop CPU&lt;/li&gt;
&lt;li&gt;one small GPU&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;you may gain access to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;hundreds of CPU cores&lt;/li&gt;
&lt;li&gt;multiple A100/H100 GPUs&lt;/li&gt;
&lt;li&gt;terabytes of memory&lt;/li&gt;
&lt;li&gt;ultra-fast networking&lt;/li&gt;
&lt;li&gt;distributed storage systems&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Systems like those hosted at CINECA are used for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AI training&lt;/li&gt;
&lt;li&gt;weather forecasting&lt;/li&gt;
&lt;li&gt;genomics&lt;/li&gt;
&lt;li&gt;computational physics&lt;/li&gt;
&lt;li&gt;climate simulations&lt;/li&gt;
&lt;li&gt;deep learning research&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Understanding the Architecture
&lt;/h1&gt;

&lt;p&gt;Most HPC systems follow this structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Your Laptop
     ↓
Login Node
     ↓
SLURM Scheduler
     ↓
Compute Nodes
     ↓
GPU/CPU Execution
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let’s simplify what each layer means.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Component&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Login Node&lt;/td&gt;
&lt;td&gt;Used for coding, editing, compiling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Compute Node&lt;/td&gt;
&lt;td&gt;Where actual jobs run&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GPU Node&lt;/td&gt;
&lt;td&gt;Used for AI and deep learning&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scheduler&lt;/td&gt;
&lt;td&gt;Manages resources and queues&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Storage System&lt;/td&gt;
&lt;td&gt;Stores datasets and outputs&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;One important rule:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Never run heavy workloads directly on login nodes.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h1&gt;
  
  
  The Biggest Mindset Shift in HPC
&lt;/h1&gt;

&lt;p&gt;On a laptop, you usually do this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Write code → Run immediately → See output
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In HPC, the workflow becomes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Write code
↓
Submit job
↓
Wait in queue
↓
Resources allocated
↓
Execution starts
↓
Logs/results generated
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;HPC is asynchronous.&lt;/p&gt;

&lt;p&gt;That is one of the biggest transitions beginners must adapt to.&lt;/p&gt;




&lt;h1&gt;
  
  
  Connecting to the Cluster
&lt;/h1&gt;

&lt;p&gt;Most HPC systems are accessed using SSH.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh username@login.clustername.cineca.it
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Modern systems may also require:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;2FA&lt;/li&gt;
&lt;li&gt;SSH certificates&lt;/li&gt;
&lt;li&gt;OTP authentication&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Linux Skills You MUST Know
&lt;/h1&gt;

&lt;p&gt;Before touching supercomputers seriously, Linux fundamentals are essential.&lt;/p&gt;

&lt;h2&gt;
  
  
  Navigation Commands
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;pwd
ls
cd
mkdir
rm
cp
mv&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  File Inspection
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cat
&lt;/span&gt;less
&lt;span class="nb"&gt;head
tail
&lt;/span&gt;nano
vim
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Process Monitoring
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;top
htop
ps
&lt;span class="nb"&gt;kill&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you are weak in Linux, HPC will feel painful very quickly.&lt;/p&gt;




&lt;h1&gt;
  
  
  Understanding Modules
&lt;/h1&gt;

&lt;p&gt;HPC environments rarely allow random software installations directly on the system.&lt;/p&gt;

&lt;p&gt;Instead, they use &lt;strong&gt;modules&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Modules dynamically load:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Python versions&lt;/li&gt;
&lt;li&gt;CUDA versions&lt;/li&gt;
&lt;li&gt;compilers&lt;/li&gt;
&lt;li&gt;MPI libraries&lt;/li&gt;
&lt;li&gt;AI frameworks&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Checking Available Modules
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;module avail
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Loading Python
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;module load python
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Viewing Loaded Modules
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;module list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Clearing Modules
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;module purge
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This prevents dependency conflicts between projects.&lt;/p&gt;




&lt;h1&gt;
  
  
  Understanding SLURM
&lt;/h1&gt;

&lt;p&gt;Most HPC systems use a scheduler called &lt;strong&gt;SLURM&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;SLURM manages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;job queues&lt;/li&gt;
&lt;li&gt;GPU allocation&lt;/li&gt;
&lt;li&gt;runtime limits&lt;/li&gt;
&lt;li&gt;cluster resources&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You do not directly “take” GPUs.&lt;/p&gt;

&lt;p&gt;You request resources from SLURM.&lt;/p&gt;




&lt;h1&gt;
  
  
  Essential SLURM Commands
&lt;/h1&gt;

&lt;h2&gt;
  
  
  View Available Partitions
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sinfo
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  View Running Jobs
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;squeue
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Submit a Job
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sbatch train.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Start Interactive Session
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;srun &lt;span class="nt"&gt;--pty&lt;/span&gt; bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Cancel a Job
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;scancel JOB_ID
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Your First SLURM Script
&lt;/h1&gt;

&lt;p&gt;Create a file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;nano train.sbatch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;
&lt;span class="c"&gt;#SBATCH --job-name=my_training&lt;/span&gt;
&lt;span class="c"&gt;#SBATCH --partition=gpu&lt;/span&gt;
&lt;span class="c"&gt;#SBATCH --nodes=1&lt;/span&gt;
&lt;span class="c"&gt;#SBATCH --ntasks=1&lt;/span&gt;
&lt;span class="c"&gt;#SBATCH --cpus-per-task=8&lt;/span&gt;
&lt;span class="c"&gt;#SBATCH --gres=gpu:1&lt;/span&gt;
&lt;span class="c"&gt;#SBATCH --time=04:00:00&lt;/span&gt;
&lt;span class="c"&gt;#SBATCH --mem=32G&lt;/span&gt;
&lt;span class="c"&gt;#SBATCH --output=output.log&lt;/span&gt;

module purge
module load cuda
module load python

python train.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Submit it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sbatch train.sbatch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;SLURM responds with something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Submitted batch job 12345
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Understanding SBATCH Parameters
&lt;/h1&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Parameter&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--job-name&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Name of the job&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--partition&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Queue name&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--nodes&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Number of machines&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--cpus-per-task&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;CPU cores&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--gres=gpu:1&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Request GPU&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--time&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Runtime limit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;--mem&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;RAM allocation&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h1&gt;
  
  
  Monitoring Jobs
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Check Queue
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;squeue &lt;span class="nt"&gt;-u&lt;/span&gt; username
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Live Monitoring
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;watch squeue &lt;span class="nt"&gt;-u&lt;/span&gt; username
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  View Job Details
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;scontrol show job 12345
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Understanding Job States
&lt;/h1&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;State&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;PD&lt;/td&gt;
&lt;td&gt;Pending&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;R&lt;/td&gt;
&lt;td&gt;Running&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CG&lt;/td&gt;
&lt;td&gt;Completing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CD&lt;/td&gt;
&lt;td&gt;Completed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;F&lt;/td&gt;
&lt;td&gt;Failed&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If your job stays in &lt;code&gt;PD&lt;/code&gt;, it usually means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;resources are busy&lt;/li&gt;
&lt;li&gt;queue is full&lt;/li&gt;
&lt;li&gt;requested resources are too large&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Interactive GPU Sessions
&lt;/h1&gt;

&lt;p&gt;Interactive sessions are useful for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;debugging&lt;/li&gt;
&lt;li&gt;notebook testing&lt;/li&gt;
&lt;li&gt;experimentation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;srun &lt;span class="nt"&gt;--partition&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;gpu &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;--gres&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;gpu:1 &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;--cpus-per-task&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;8 &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;--mem&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;32G &lt;span class="se"&gt;\&lt;/span&gt;
     &lt;span class="nt"&gt;--pty&lt;/span&gt; bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Python Environments on HPC
&lt;/h1&gt;

&lt;p&gt;Never rely entirely on system Python for serious AI work.&lt;/p&gt;

&lt;p&gt;Most researchers use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Conda&lt;/li&gt;
&lt;li&gt;virtual environments&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Create Environment
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;conda create &lt;span class="nt"&gt;-n&lt;/span&gt; ml &lt;span class="nv"&gt;python&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;3.11
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Activate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;conda activate ml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install packages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;torch transformers datasets
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  GPU Training Workflow
&lt;/h1&gt;

&lt;p&gt;A common AI workflow looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Local Machine
    ↓
Upload Dataset
    ↓
Prepare Environment
    ↓
Write SLURM Script
    ↓
Submit Training
    ↓
Monitor Logs
    ↓
Download Results
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Storage Systems Matter More Than Beginners Think
&lt;/h1&gt;

&lt;p&gt;HPC systems typically have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;home storage&lt;/li&gt;
&lt;li&gt;scratch storage&lt;/li&gt;
&lt;li&gt;project storage&lt;/li&gt;
&lt;li&gt;high-speed temporary storage&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A common beginner mistake is training directly from slow home directories.&lt;/p&gt;

&lt;p&gt;For large AI workloads:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;use scratch storage&lt;/li&gt;
&lt;li&gt;optimize data loading&lt;/li&gt;
&lt;li&gt;clean temporary files regularly&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Transferring Files
&lt;/h1&gt;

&lt;h2&gt;
  
  
  SCP Example
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;scp dataset.zip username@cluster:/scratch/project/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  RSYNC Example
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;rsync &lt;span class="nt"&gt;-av&lt;/span&gt; dataset/ username@cluster:/scratch/project/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Running PyTorch on HPC
&lt;/h1&gt;

&lt;p&gt;Simple GPU check:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;

&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cuda&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_available&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="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cuda&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_device_name&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;SLURM script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#SBATCH --gres=gpu:1&lt;/span&gt;

python train.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Multi-GPU Training
&lt;/h1&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#SBATCH --nodes=1&lt;/span&gt;
&lt;span class="c"&gt;#SBATCH --gres=gpu:4&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;PyTorch distributed execution:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;torchrun &lt;span class="nt"&gt;--nproc_per_node&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;4 train.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is where HPC becomes significantly more powerful than normal laptops.&lt;/p&gt;




&lt;h1&gt;
  
  
  MPI and Distributed Computing
&lt;/h1&gt;

&lt;p&gt;Scientific applications often use MPI.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;module load openmpi

mpirun &lt;span class="nt"&gt;-np&lt;/span&gt; 16 ./simulation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;MPI is heavily used in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;physics&lt;/li&gt;
&lt;li&gt;computational fluid dynamics&lt;/li&gt;
&lt;li&gt;simulations&lt;/li&gt;
&lt;li&gt;weather forecasting&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Containers in HPC
&lt;/h1&gt;

&lt;p&gt;Unlike cloud-native environments that heavily use Docker, HPC systems often use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Singularity&lt;/li&gt;
&lt;li&gt;Apptainer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;module load singularity
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;singularity &lt;span class="nb"&gt;exec &lt;/span&gt;container.sif python train.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h1&gt;
  
  
  Common Beginner Mistakes
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Running Heavy Jobs on Login Nodes
&lt;/h2&gt;

&lt;p&gt;This annoys system administrators very quickly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Requesting Too Many Resources
&lt;/h2&gt;

&lt;p&gt;Large requests stay longer in queue.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ignoring Logs
&lt;/h2&gt;

&lt;p&gt;Logs explain most failures.&lt;/p&gt;

&lt;p&gt;Example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;tail&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; output.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  CUDA Version Mismatches
&lt;/h2&gt;

&lt;p&gt;Your PyTorch CUDA version must match cluster CUDA support.&lt;/p&gt;




&lt;h1&gt;
  
  
  HPC vs Cloud GPUs
&lt;/h1&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;HPC&lt;/th&gt;
&lt;th&gt;Cloud&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Shared infrastructure&lt;/td&gt;
&lt;td&gt;Commercial infrastructure&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Often research-funded&lt;/td&gt;
&lt;td&gt;Pay-as-you-go&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Queue-based&lt;/td&gt;
&lt;td&gt;Immediate provisioning&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Strong interconnects&lt;/td&gt;
&lt;td&gt;Flexible scaling&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Excellent for huge workloads&lt;/td&gt;
&lt;td&gt;Excellent for startups&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h1&gt;
  
  
  Recommended Learning Path
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Stage 1 — Linux
&lt;/h2&gt;

&lt;p&gt;Learn:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;bash&lt;/li&gt;
&lt;li&gt;file systems&lt;/li&gt;
&lt;li&gt;SSH&lt;/li&gt;
&lt;li&gt;permissions&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Stage 2 — SLURM
&lt;/h2&gt;

&lt;p&gt;Learn:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;job submission&lt;/li&gt;
&lt;li&gt;monitoring&lt;/li&gt;
&lt;li&gt;partitions&lt;/li&gt;
&lt;li&gt;scheduling&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Stage 3 — Python Environments
&lt;/h2&gt;

&lt;p&gt;Learn:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Conda&lt;/li&gt;
&lt;li&gt;CUDA&lt;/li&gt;
&lt;li&gt;pip&lt;/li&gt;
&lt;li&gt;virtual environments&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Stage 4 — GPU Computing
&lt;/h2&gt;

&lt;p&gt;Learn:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PyTorch&lt;/li&gt;
&lt;li&gt;distributed training&lt;/li&gt;
&lt;li&gt;checkpointing&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Stage 5 — Advanced HPC
&lt;/h2&gt;

&lt;p&gt;Learn:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MPI&lt;/li&gt;
&lt;li&gt;NCCL&lt;/li&gt;
&lt;li&gt;DeepSpeed&lt;/li&gt;
&lt;li&gt;multi-node training&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Practice Projects for Beginners
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Beginner
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Submit hello-world SLURM job&lt;/li&gt;
&lt;li&gt;Train MNIST on GPU&lt;/li&gt;
&lt;li&gt;Monitor job states&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Intermediate
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Multi-GPU image classifier&lt;/li&gt;
&lt;li&gt;Jupyter on HPC&lt;/li&gt;
&lt;li&gt;Distributed preprocessing pipeline&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Advanced
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;DeepSpeed training&lt;/li&gt;
&lt;li&gt;MPI simulations&lt;/li&gt;
&lt;li&gt;Large language model fine-tuning&lt;/li&gt;
&lt;/ul&gt;




&lt;h1&gt;
  
  
  Final Thoughts
&lt;/h1&gt;

&lt;p&gt;The people who stand out in HPC environments are usually not just the best programmers.&lt;/p&gt;

&lt;p&gt;They are the people who understand:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;systems&lt;/li&gt;
&lt;li&gt;optimization&lt;/li&gt;
&lt;li&gt;storage bottlenecks&lt;/li&gt;
&lt;li&gt;resource management&lt;/li&gt;
&lt;li&gt;debugging workflows&lt;/li&gt;
&lt;li&gt;automation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Supercomputing is less about “running code fast” and more about learning how to think computationally at scale.&lt;/p&gt;

&lt;p&gt;If you are entering AI, scientific computing, or large-scale machine learning research, learning HPC may become one of the most valuable technical skills you acquire.&lt;/p&gt;




&lt;h1&gt;
  
  
  Useful Resources
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.hpc.cineca.it/?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;CINECA HPC Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://slurm.schedmd.com/documentation.html?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;SLURM Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://pytorch.org/tutorials/intermediate/ddp_tutorial.html?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;PyTorch Distributed Training Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.open-mpi.org/doc/?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;OpenMPI Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://apptainer.org/docs/?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Apptainer Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;If you are already working with supercomputers or HPC clusters, what was the hardest concept for you when you first started?&lt;/p&gt;

</description>
      <category>gpu</category>
      <category>cluster</category>
      <category>supercomputers</category>
      <category>ai</category>
    </item>
    <item>
      <title>Docker Cheat Sheet: Commands Every Developer Should Know</title>
      <dc:creator>Ikegbo Ogochukwu</dc:creator>
      <pubDate>Tue, 12 May 2026 18:57:12 +0000</pubDate>
      <link>https://dev.to/kenryikegbo/-docker-cheat-sheet-commands-every-developer-should-know-1aj0</link>
      <guid>https://dev.to/kenryikegbo/-docker-cheat-sheet-commands-every-developer-should-know-1aj0</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Docker helps you package an application with everything it needs to run: code, dependencies, environment variables, and runtime settings. This cheat sheet covers the most useful Docker commands for daily development.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Check Docker Installation
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nt"&gt;--version&lt;/span&gt;
docker info
docker &lt;span class="nb"&gt;help&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  2. Docker Images
&lt;/h2&gt;

&lt;h3&gt;
  
  
  List images
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker images
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Pull an image
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker pull nginx
docker pull python:3.12
docker pull node:20
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Remove an image
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker rmi image_name
docker rmi image_id
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Build an image from a Dockerfile
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; my-app &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Build with a specific Dockerfile
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;-f&lt;/span&gt; Dockerfile.dev &lt;span class="nt"&gt;-t&lt;/span&gt; my-app-dev &lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  3. Docker Containers
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Run a container
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Run container in detached mode
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-d&lt;/span&gt; nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Run container with a name
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--name&lt;/span&gt; my-nginx nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Run container and map ports
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-p&lt;/span&gt; 8080:80 nginx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This maps port &lt;code&gt;8080&lt;/code&gt; on your computer to port &lt;code&gt;80&lt;/code&gt; inside the container.&lt;/p&gt;

&lt;h3&gt;
  
  
  Run container with environment variables
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;APP_ENV&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;development my-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Run container interactively
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-it&lt;/span&gt; ubuntu bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  4. List Containers
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Running containers
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker ps
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  All containers
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker ps &lt;span class="nt"&gt;-a&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  5. Stop, Start, Restart Containers
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker stop container_name
docker start container_name
docker restart container_name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  6. Remove Containers
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Remove one container
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;rm &lt;/span&gt;container_name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Remove all stopped containers
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker container prune
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  7. Logs and Debugging
&lt;/h2&gt;

&lt;h3&gt;
  
  
  View logs
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker logs container_name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Follow logs live
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker logs &lt;span class="nt"&gt;-f&lt;/span&gt; container_name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Enter a running container
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; container_name bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;bash&lt;/code&gt; is not available:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; container_name sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Inspect container details
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker inspect container_name
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  8. Volumes
&lt;/h2&gt;

&lt;p&gt;Volumes help you persist data outside the container.&lt;/p&gt;

&lt;h3&gt;
  
  
  Create a volume
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker volume create my-volume
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  List volumes
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker volume &lt;span class="nb"&gt;ls&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Use a volume
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-v&lt;/span&gt; my-volume:/app/data my-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Remove a volume
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker volume &lt;span class="nb"&gt;rm &lt;/span&gt;my-volume
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Remove unused volumes
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker volume prune
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  9. Bind Mounts
&lt;/h2&gt;

&lt;p&gt;Bind mounts connect a folder on your computer to a folder inside the container.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;:/app my-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On Windows PowerShell:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;docker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;run&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-v&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;${PWD}&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;/app&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;my-app&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  10. Networks
&lt;/h2&gt;

&lt;h3&gt;
  
  
  List networks
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker network &lt;span class="nb"&gt;ls&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Create a network
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker network create my-network
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Run container on a network
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--network&lt;/span&gt; my-network &lt;span class="nt"&gt;--name&lt;/span&gt; app my-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Remove a network
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker network &lt;span class="nb"&gt;rm &lt;/span&gt;my-network
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  11. Dockerfile Example
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; python:3.12-slim&lt;/span&gt;

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; requirements.txt .&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--no-cache-dir&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; . .&lt;/span&gt;

&lt;span class="k"&gt;EXPOSE&lt;/span&gt;&lt;span class="s"&gt; 8000&lt;/span&gt;

&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["python", "app.py"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  12. Docker Compose
&lt;/h2&gt;

&lt;p&gt;Docker Compose helps you run multiple containers together.&lt;/p&gt;

&lt;h3&gt;
  
  
  Example &lt;code&gt;docker-compose.yml&lt;/code&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;app&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;.&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;8000:8000"&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;APP_ENV=development&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;.:/app&lt;/span&gt;

  &lt;span class="na"&gt;database&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;postgres:16&lt;/span&gt;
    &lt;span class="na"&gt;environment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_USER=admin&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_PASSWORD=password&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;POSTGRES_DB=mydb&lt;/span&gt;
    &lt;span class="na"&gt;ports&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;5432:5432"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Start services
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Start in detached mode
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Stop services
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose down
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Rebuild services
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose up &lt;span class="nt"&gt;--build&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  View logs
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose logs
docker compose logs &lt;span class="nt"&gt;-f&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  13. Cleaning Up Docker
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Remove unused data
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker system prune
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Remove unused data including images
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker system prune &lt;span class="nt"&gt;-a&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Remove unused containers
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker container prune
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Remove unused images
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker image prune
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Remove unused volumes
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker volume prune
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Be careful with prune commands because they delete unused Docker resources.&lt;/p&gt;




&lt;h2&gt;
  
  
  14. Common Docker Commands Summary
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker build &lt;span class="nt"&gt;-t&lt;/span&gt; my-app &lt;span class="nb"&gt;.&lt;/span&gt;
docker run &lt;span class="nt"&gt;-p&lt;/span&gt; 8000:8000 my-app
docker ps
docker ps &lt;span class="nt"&gt;-a&lt;/span&gt;
docker stop container_name
docker start container_name
docker restart container_name
docker &lt;span class="nb"&gt;rm &lt;/span&gt;container_name
docker rmi image_name
docker logs &lt;span class="nt"&gt;-f&lt;/span&gt; container_name
docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; container_name bash
docker system prune
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  15. Useful Docker Compose Commands Summary
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker compose up
docker compose up &lt;span class="nt"&gt;-d&lt;/span&gt;
docker compose down
docker compose up &lt;span class="nt"&gt;--build&lt;/span&gt;
docker compose logs &lt;span class="nt"&gt;-f&lt;/span&gt;
docker compose ps
docker compose &lt;span class="nb"&gt;exec &lt;/span&gt;app bash
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Final Note
&lt;/h2&gt;

&lt;p&gt;Docker is powerful because it makes your application easier to run, share, test, and deploy. Once you understand images, containers, volumes, networks, and Docker Compose, you can package almost any application into a reproducible environment.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>containers</category>
      <category>virtualmachine</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>Implementing Facebook Login in Flutter with Meta and Firebase: The Configuration Guide Most Teams Actually Need</title>
      <dc:creator>Ikegbo Ogochukwu</dc:creator>
      <pubDate>Mon, 11 May 2026 22:33:07 +0000</pubDate>
      <link>https://dev.to/kenryikegbo/implementing-facebook-login-in-flutter-with-meta-and-firebase-the-configuration-guide-most-teams-3cci</link>
      <guid>https://dev.to/kenryikegbo/implementing-facebook-login-in-flutter-with-meta-and-firebase-the-configuration-guide-most-teams-3cci</guid>
      <description>&lt;h2&gt;
  
  
  Subtitle
&lt;/h2&gt;

&lt;p&gt;How to set up Meta for Developers, Business ownership, Firebase Authentication, and native mobile config without mixing up App Domains, key hashes, and redirect URIs&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Facebook Login looks simple from the Flutter side. In code, it can be as small as calling &lt;code&gt;FacebookAuth.instance.login()&lt;/code&gt;, converting the token to a Firebase credential, and signing the user in.&lt;/p&gt;

&lt;p&gt;The real complexity is not in the Dart code. It is in the configuration spread across four systems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developers.facebook.com/?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Meta for Developers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Meta Business ownership and app access&lt;/li&gt;
&lt;li&gt;&lt;a href="https://firebase.google.com/docs/auth?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Firebase Authentication&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Native Android and iOS app configuration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If one of those layers is misconfigured, the failure usually shows up as a vague login cancellation, invalid OAuth redirect, key-hash error, or a token exchange failure. That is why treating Facebook Login as a console-configuration workflow, not only a code task, saves time.&lt;/p&gt;

&lt;p&gt;This guide explains the full setup path using abstract examples instead of production identifiers.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Understand the flow before configuring anything
&lt;/h2&gt;

&lt;p&gt;In a Firebase-backed Flutter app, the Facebook login flow usually works like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The app launches the Facebook login flow using the native Facebook SDK through a Flutter plugin.&lt;/li&gt;
&lt;li&gt;Facebook returns an access token to the app.&lt;/li&gt;
&lt;li&gt;The app converts that Facebook token into a Firebase credential.&lt;/li&gt;
&lt;li&gt;Firebase signs the user in and issues a Firebase ID token.&lt;/li&gt;
&lt;li&gt;Your backend can then verify the Firebase token and create or update the app-specific user session.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That means Meta is not replacing Firebase. Meta is the identity provider, Firebase is the authentication broker, and your backend remains the application session authority if your product uses its own access and refresh tokens.&lt;/p&gt;




&lt;h2&gt;
  
  
  2. Start with a real Meta developer account
&lt;/h2&gt;

&lt;p&gt;Before you can create a Facebook app, you need to register as a Meta developer.&lt;/p&gt;

&lt;p&gt;Meta's developer registration flow requires:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a Facebook account&lt;/li&gt;
&lt;li&gt;agreement to Meta's platform terms and policies&lt;/li&gt;
&lt;li&gt;verification of your account contact details&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Meta's documentation states that developer verification is based on confirming the phone number and email address you provide for developer notifications. In practice, the exact verification flow can vary depending on the account and region.&lt;/p&gt;

&lt;p&gt;The practical takeaway is simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;do not build the app under a throwaway personal Facebook account&lt;/li&gt;
&lt;li&gt;use an account your organization can retain access to&lt;/li&gt;
&lt;li&gt;enable two-factor authentication&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Useful references:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developers.facebook.com/docs/development/register?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Meta Developer Registration Docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.facebook.com/security/2fac/setup/intro?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Meta Security Center&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  3. Use a Business-owned app, not a personal orphan app
&lt;/h2&gt;

&lt;p&gt;This is the part many teams skip until they run into access problems.&lt;/p&gt;

&lt;p&gt;Even if a single developer creates the app initially, the long-term owner should be the business, not one person's personal account. A proper Meta Business portfolio helps with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;shared ownership&lt;/li&gt;
&lt;li&gt;teammate access&lt;/li&gt;
&lt;li&gt;future app review or verification requests&lt;/li&gt;
&lt;li&gt;preserving control if a developer leaves&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a simple Facebook Login integration that only requests minimal data, business verification may not be the first blocker. But for production ownership, review, and future scaling, organizing the app under the correct business from the beginning is still the better decision.&lt;/p&gt;

&lt;p&gt;Keep this distinction clear:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;developer account: the person who can access Meta for Developers&lt;/li&gt;
&lt;li&gt;business portfolio: the organization that should own the app and related assets&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  4. Meta app setup has three different configuration buckets
&lt;/h2&gt;

&lt;p&gt;This is where the confusion usually starts. Developers often mix up values that belong in completely different places.&lt;/p&gt;

&lt;h3&gt;
  
  
  Basic Settings
&lt;/h3&gt;

&lt;p&gt;This area is about the identity of your Meta app.&lt;/p&gt;

&lt;p&gt;Typical values here include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;app name&lt;/li&gt;
&lt;li&gt;app contact email&lt;/li&gt;
&lt;li&gt;privacy policy URL&lt;/li&gt;
&lt;li&gt;app domains&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The important trap: &lt;code&gt;App Domains&lt;/code&gt; is not the same thing as Firebase's OAuth redirect URI.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;App Domains&lt;/code&gt; should represent the real public domain associated with your app or website. In practice, this is the host that serves your public web presence or policy pages.&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;exampleapp.com&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;auth.exampleapp.com&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do &lt;strong&gt;not&lt;/strong&gt; put these in &lt;code&gt;App Domains&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;https://sample-project.firebaseapp.com/__/auth/handler&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;any URL with &lt;code&gt;https://&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;callback paths&lt;/li&gt;
&lt;li&gt;&lt;code&gt;localhost&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Android package names&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That guidance aligns with how Meta uses the field. OAuth redirect URIs belong elsewhere.&lt;/p&gt;

&lt;h3&gt;
  
  
  Facebook Login product settings
&lt;/h3&gt;

&lt;p&gt;This is where you configure login-specific callback handling.&lt;/p&gt;

&lt;p&gt;If you use Firebase Authentication with Facebook as a provider, Firebase requires the OAuth redirect URI from Firebase Console to be added to your Facebook app.&lt;/p&gt;

&lt;p&gt;Example redirect URI:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://sample-project.firebaseapp.com/__/auth/handler
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This belongs in:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Facebook Login&lt;/li&gt;
&lt;li&gt;Settings&lt;/li&gt;
&lt;li&gt;Valid OAuth Redirect URIs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Reference:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://firebase.google.com/docs/auth/flutter/federated-auth?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Firebase Federated Authentication Docs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Platform settings
&lt;/h3&gt;

&lt;p&gt;Meta also needs to know which native apps are allowed to use the Meta app.&lt;/p&gt;

&lt;p&gt;For Android, Meta requires:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;package name&lt;/li&gt;
&lt;li&gt;default activity class&lt;/li&gt;
&lt;li&gt;development and release key hashes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For iOS, Meta requires:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;bundle identifier registration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These are platform identity values, not OAuth redirect values.&lt;/p&gt;

&lt;p&gt;References:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developers.facebook.com/docs/facebook-login/android?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Meta Facebook Login for Android&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.facebook.com/docs/facebook-login/ios?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Meta Facebook Login for iOS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  5. Firebase sits in the middle of the sign-in flow
&lt;/h2&gt;

&lt;p&gt;Firebase's Flutter authentication documentation describes the Facebook setup in a very direct way:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;create a Facebook Developer App&lt;/li&gt;
&lt;li&gt;enable Facebook provider in Firebase Console&lt;/li&gt;
&lt;li&gt;add the Facebook App ID and App Secret&lt;/li&gt;
&lt;li&gt;use a native Facebook SDK path on Android and iOS&lt;/li&gt;
&lt;li&gt;authenticate using &lt;code&gt;FacebookAuthProvider.credential(...)&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Firebase also highlights two important details:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the Facebook provider must be enabled in Firebase Console&lt;/li&gt;
&lt;li&gt;the Firebase OAuth redirect URI must be added to the Facebook app&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is why setup order matters. If Meta is configured but Firebase is not, the native token may be returned while Firebase authentication still fails.&lt;/p&gt;

&lt;p&gt;Reference:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://firebase.google.com/docs/auth/flutter/federated-auth?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Firebase Auth for Flutter&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  6. Native mobile config still matters in a Flutter project
&lt;/h2&gt;

&lt;p&gt;Flutter does not remove the need for native Facebook settings.&lt;/p&gt;

&lt;p&gt;Meta's Android setup requires:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;facebook_app_id&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;facebook_client_token&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;fb_login_protocol_scheme&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;manifest metadata&lt;/li&gt;
&lt;li&gt;Facebook activities&lt;/li&gt;
&lt;li&gt;Custom Tab configuration&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;INTERNET&lt;/code&gt; permission&lt;/li&gt;
&lt;li&gt;package/class association&lt;/li&gt;
&lt;li&gt;key hashes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Meta's iOS setup requires:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;CFBundleURLSchemes&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;FacebookAppID&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;FacebookClientToken&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;FacebookDisplayName&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;LSApplicationQueriesSchemes&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;bundle ID registration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Even in Flutter, Facebook Login still relies on native Android and iOS configuration under the hood.&lt;/p&gt;




&lt;h2&gt;
  
  
  7. What a properly configured project usually contains
&lt;/h2&gt;

&lt;p&gt;In a typical Flutter + Firebase + Facebook Login project, you will usually have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;flutter_facebook_auth&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;a login flow calling &lt;code&gt;FacebookAuth.instance.login()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Firebase credential conversion&lt;/li&gt;
&lt;li&gt;Android package identifiers&lt;/li&gt;
&lt;li&gt;iOS bundle identifiers&lt;/li&gt;
&lt;li&gt;native Android metadata&lt;/li&gt;
&lt;li&gt;iOS &lt;code&gt;Info.plist&lt;/code&gt; Facebook entries&lt;/li&gt;
&lt;li&gt;Firebase Authentication enabled&lt;/li&gt;
&lt;li&gt;a configured Firebase auth domain&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;At that stage, the remaining work is often:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;aligning Meta console settings with native identifiers&lt;/li&gt;
&lt;li&gt;adding Android debug and release key hashes&lt;/li&gt;
&lt;li&gt;enabling Facebook provider in Firebase&lt;/li&gt;
&lt;li&gt;confirming the correct ownership and admin structure&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  8. Business portfolio is operational hygiene, not bureaucracy
&lt;/h2&gt;

&lt;p&gt;If you are building a real product, business ownership matters for reasons beyond compliance.&lt;/p&gt;

&lt;p&gt;Without proper business ownership, you can run into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;one developer privately owning the Meta app&lt;/li&gt;
&lt;li&gt;broken access when people leave the team&lt;/li&gt;
&lt;li&gt;confusion over who can submit apps for review&lt;/li&gt;
&lt;li&gt;delays when Meta later requests verification&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a small team, the disciplined approach is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;create or select the correct business portfolio&lt;/li&gt;
&lt;li&gt;make the business the long-term owner&lt;/li&gt;
&lt;li&gt;assign appropriate admin and developer roles&lt;/li&gt;
&lt;li&gt;keep business documentation ready if verification is requested&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  9. Testing should happen in stages
&lt;/h2&gt;

&lt;p&gt;A reliable testing sequence looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Confirm Facebook provider is enabled in Firebase.&lt;/li&gt;
&lt;li&gt;Confirm Android and iOS platform values are correct in Meta.&lt;/li&gt;
&lt;li&gt;Add Android debug key hash and test debug builds.&lt;/li&gt;
&lt;li&gt;Add Android release key hash and test release builds.&lt;/li&gt;
&lt;li&gt;Test iOS on a real device if shipping on iOS.&lt;/li&gt;
&lt;li&gt;Confirm Firebase user creation succeeds.&lt;/li&gt;
&lt;li&gt;Confirm backend session creation succeeds.&lt;/li&gt;
&lt;li&gt;Test logout and account deletion flows.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If you only test debug Android builds, you can still ship a broken production login flow.&lt;/p&gt;




&lt;h2&gt;
  
  
  10. Common mistakes to avoid
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;putting the Firebase redirect URI into &lt;code&gt;App Domains&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;forgetting Android release key hashes&lt;/li&gt;
&lt;li&gt;enabling Facebook Login in Meta but not in Firebase&lt;/li&gt;
&lt;li&gt;exposing the Facebook App Secret in Flutter code&lt;/li&gt;
&lt;li&gt;registering the app under the wrong personal account&lt;/li&gt;
&lt;li&gt;assuming Flutter removes native setup requirements&lt;/li&gt;
&lt;li&gt;testing only in development mode&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Final takeaway
&lt;/h2&gt;

&lt;p&gt;Facebook Login in Flutter is not mainly a Dart problem. It is a configuration and ownership problem.&lt;/p&gt;

&lt;p&gt;The teams that get it right usually do four things well:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;they create the Meta app under a durable owner&lt;/li&gt;
&lt;li&gt;they align Meta settings, Firebase settings, and native mobile settings&lt;/li&gt;
&lt;li&gt;they understand the difference between &lt;code&gt;App Domains&lt;/code&gt; and OAuth redirect URIs&lt;/li&gt;
&lt;li&gt;they test both debug and release login paths&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Once those pieces are aligned, the Flutter implementation becomes the easy part.&lt;/p&gt;




&lt;h2&gt;
  
  
  Sources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developers.facebook.com/docs/development/register?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Meta Developer Registration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.facebook.com/docs/facebook-login/android?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Meta Facebook Login for Android&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developers.facebook.com/docs/facebook-login/ios?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Meta Facebook Login for iOS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://firebase.google.com/docs/auth/flutter/federated-auth?utm_source=chatgpt.com" rel="noopener noreferrer"&gt;Firebase Flutter Federated Authentication Docs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>flutter</category>
      <category>mobile</category>
      <category>android</category>
      <category>auth0challenge</category>
    </item>
  </channel>
</rss>
