Sunday, November 1, 2026

Generics in Java - Viva Questions

 Give me viva questions and answers for 5 questions on generics in java single line question and answer

1. What are generics in Java?
Generics allow classes, interfaces, and methods to operate on typed parameters, enabling compile-time type safety without casting.

2. What is type erasure?
It's the process by which the compiler removes generic type information after compilation, replacing type parameters with their bounds or Object for backward compatibility.

3. What is the difference between List<Object> and raw type List?
List<Object> is type-checked at compile time for Object elements, while a raw List bypasses generic type checking, triggering unchecked warnings.

4. What are bounded type parameters, and how are they declared?
They restrict the types that can be used as arguments, declared using extends (e.g., <T extends Number>) to allow only that type or its subtypes.

5. What is a wildcard in generics, and what are its types?
A wildcard (?) represents an unknown type, with three forms: unbounded (?), upper-bounded (? extends T), and lower-bounded (? super T).

Saturday, October 31, 2026

Jenkins Security Warnings- A few warnings overlooked means build system is compromised


Jenkins Security Warnings: Understanding Vulnerabilities, Available Fixes, and Remediation

An administrator’s perspective on reviewing Jenkins core and plugin security warnings

Jenkins is widely used to automate software builds, testing, and deployment. Like any extensible automation server, its security depends on both the Jenkins core and the plugins installed alongside it.

While reviewing my Jenkins installation, I encountered a dashboard containing multiple security warnings. These included vulnerabilities in Jenkins core, authentication plugins, Pipeline components, and libraries used for email and cryptographic operations.

This article documents those warnings, explains their technical implications, distinguishes between vulnerabilities with fixes and those reported without fixes at the time of observation, and outlines a practical remediation strategy.

Important: The findings below originate from a Jenkins dashboard snapshot showing Jenkins 2.462.3. I have cross-checked selected issues against the official Jenkins security advisories available on 1 November 2026. The status displayed in the original snapshot is not necessarily the current remediation status.

1. Understanding the different types of warnings

Not every warning has the same significance.

  • Security vulnerability: A weakness that may compromise confidentiality, integrity, or availability.

  • Fix available: A corrected release has been published, and the affected component should be upgraded.

  • No fix available at the time of observation: The dashboard did not identify a corrected release. Administrators should check the latest advisory before deciding whether to retain the component.

  • Remediation status not visible: The available screenshot does not contain enough information to determine whether a fix exists.

The distinction matters because a vulnerability is not automatically evidence that an installation has been compromised. Its actual risk depends on the affected functionality, permissions, configuration, network exposure, and available mitigations.

2. Jenkins core security vulnerabilities

My dashboard identified multiple security advisories affecting older Jenkins releases, including advisories covering Jenkins 2.499, 2.527, 2.550, 2.554, 2.575, 2.587, and other release ranges.

It also listed a denial-of-service vulnerability in the bundled json-lib library.

What is the risk?

Jenkins core manages jobs, credentials, permissions, agents, configuration files, and interactions between plugins. A vulnerability in the core can therefore affect a wide range of operations.

Depending on the specific defect, the consequences of core vulnerabilities may include:

  • Unauthorized access to configuration or information.

  • Improper permission enforcement.

  • Cross-site scripting (XSS).

  • Path traversal and unintended file access.

  • Unsafe object deserialization, potentially leading to remote code execution.

  • Denial of service.

These are examples of vulnerability classes, not a claim that every advisory listed on my dashboard permits all these outcomes.

A denial-of-service vulnerability is particularly relevant to availability: specially crafted input may consume excessive resources or otherwise disrupt service.

Remediation

The Jenkins security advisory published on 28 October 2026 documents multiple core vulnerabilities affecting Jenkins weekly releases through 2.587 and LTS releases through 2.580.1. The advisory identifies Jenkins 2.588 and LTS 2.580.2 as fixed releases.

My dashboard displayed Jenkins 2.580.2 as an available update, while the installed core version was 2.462.3. Upgrading to a supported, security-fixed release is therefore a priority.

Official references:

3. LDAP Plugin: SSRF and remote code execution

The installed LDAP Plugin was reported with two vulnerabilities:

  1. Improper access control allowing server-side request forgery (SSRF).

  2. Remote code execution associated with unvalidated LDAP referrals.

Technical implications

Server-side request forgery (SSRF) occurs when an attacker can cause a server to make requests to destinations that should not be accessible through the intended interface. Depending on the server's network position and permissions, this may expose internal services or enable unintended interactions.

The LDAP referral issue is more serious than a simple directory lookup error. According to the official Jenkins advisory, unvalidated LDAP referrals can direct Jenkins to an RMI URL that triggers deserialization of attacker-controlled data, potentially allowing code execution on the Jenkins controller under vulnerable conditions.

The documented attack scenario involves an attacker who controls the configured LDAP server or can perform a machine-in-the-middle attack.

Remediation

The official advisories identify fixed LDAP Plugin releases. In particular, the September 2026 advisory identifies version 825.v2fca_37dd5b_cb_ as fixing the SSRF issue, while the May 2026 advisory describes the referral-related RCE vulnerability and its fix.

Update the plugin to a compatible, fixed release and review the configuration of LDAP authentication and referrals.

References:

4. Gradle Plugin: SSRF and Develocity access-key exposure

The dashboard reported an SSRF vulnerability that could allow the capture of a Develocity access key. At the time represented by the screenshot, Jenkins displayed the issue as having no fix available.

Why is this significant?

Build systems frequently interact with external services, artifact repositories, and build analytics platforms. Access keys used by these services must be protected from unintended disclosure.

The official September 2026 advisory explains that vulnerable versions of the Gradle Plugin could request build-scan data from a URL detected in build logs, even when a Develocity server URL was configured globally. An attacker able to control the build log could exploit this behavior to cause a request to an attacker-specified URL and potentially capture the configured access key.

Remediation status

The original dashboard status is no longer sufficient to determine the current fix status.

The official advisory identifies Gradle Plugin version 2.20.1253.vc116f0763a_eb_ as fixing the issue.

Administrators should update to a compatible fixed release and review access keys that may have been exposed. If there is evidence of possible compromise, consider rotating the affected credentials.

Reference: Jenkins Security Advisory — 16 September 2026

5. GitHub Branch Source Plugin: Missing permission checks

The screenshot listed two issues:

  • A missing permission check that could allow enumeration of GitHub Enterprise server URLs.

  • A missing permission check that could allow a connection test to be performed.

Technical implications

Permission checks are fundamental to Jenkins security. A user should only be able to access information or trigger operations permitted by their assigned role.

The first vulnerability can disclose the URLs of GitHub Enterprise servers configured by an administrator. Such information may reveal internal infrastructure details.

The second issue concerns authorization around connection testing. The exact impact depends on the affected endpoint and the permissions required to exploit it.

Remediation status

Although the dashboard originally stated that no fix was available, the official June 2026 advisory identifies a fixed GitHub Branch Source Plugin version, 1967.1970.vd86979736546, for the server-URL enumeration issue.

The installed version shown in my screenshot was 1807.v50351eb_7dd13, which is substantially older than the version identified in that advisory.

Update to a compatible fixed version and review the advisory for the connection-test issue before concluding that both findings have been resolved.

Reference: Jenkins Security Advisory — 24 June 2026

6. EDD SA API Plugin: EdDSA signature malleability

The dashboard reported a signature-malleability vulnerability in the EdDSA implementation bundled with the EDD SA API Plugin.

What is signature malleability?

Digital signatures are used to establish the authenticity and integrity of messages. Signature malleability means that a message may have multiple valid signature representations, potentially undermining systems that rely on signatures being unique.

The official Jenkins advisory explains that the affected library did not satisfy the Strong Existential Unforgeability under Chosen Message Attacks (SUF-CMA) property.

The practical impact depends on how consuming components generate, verify, and use signatures.

Remediation

The official advisory identifies 0.3.0.1-16.vcb_4a_98a_3531c as a fixed release of the EDD SA API Plugin.

Reference: Jenkins Security Advisory — 19 March 2025

7. Pipeline: Groovy Plugin

The screenshot listed two security issues:

  • A CSRF vulnerability combined with unrestricted type instantiation.

  • Rebuilding a run after its script approval had been revoked.

Technical implications

Cross-site request forgery (CSRF) occurs when an attacker can induce a user's authenticated browser session to submit an unwanted request.

Unrestricted type instantiation can weaken security boundaries by allowing objects to be created in ways that were not intended by the application's security model.

The script-approval issue is especially relevant to Pipeline security. If an administrator revokes approval for a script, subsequent operations should respect that decision. Allowing a run to be rebuilt despite revoked approval can undermine the approval mechanism.

Remediation

The dashboard indicated that fixes were available. Update the Pipeline: Groovy Plugin to a compatible fixed release and verify the advisory corresponding to each reported issue.

Review script approvals, limit permission to configure and rebuild jobs, and avoid granting broad administrative access to users who only need to run builds.

8. Jakarta Mail API Plugin: SMTP command injection

The screenshot began listing an SMTP command injection vulnerability but did not show the complete remediation information.

Technical implications

SMTP command injection can occur when untrusted input is incorporated into email operations without adequate validation. An attacker may be able to influence the commands or recipients used by a mail client.

The official Jenkins advisory of 3 September 2025 identifies CVE-2025-7962 in vulnerable versions of the Jakarta Mail API Plugin. The documented impact includes allowing attackers who control recipient email addresses used by Jenkins to send messages with arbitrary contents to arbitrary recipients.

Remediation status

The original screenshot does not reveal the remediation status, but the official advisory identifies version 2.1.3-3 as fixed.

Update the plugin to a compatible fixed release and review how recipient addresses are obtained and validated in Jenkins jobs and notification configurations.

Reference: Jenkins Security Advisory — 3 September 2025

9. Summary of vulnerability and remediation status

The following table distinguishes the original dashboard observation from the remediation information in the official advisories reviewed for this article.

ComponentVulnerabilityRemediation information
Jenkins coreMultiple security vulnerabilitiesFixed LTS release identified: 2.580.2
Bundled json-libDenial of serviceOriginal screenshot reports the issue; verify the applicable fixed release through the relevant advisory
LDAP PluginSSRF and unvalidated LDAP referralsFixed releases identified
Gradle PluginSSRF and Develocity access-key exposureFixed release identified after the screenshot's reported status
GitHub Branch Source PluginMissing permission checksFixed release identified for URL enumeration; verify the connection-test issue separately
EDD SA API PluginEdDSA signature malleabilityFixed release identified
Pipeline: Groovy PluginCSRF, type instantiation, and script-approval controlDashboard reports fixes available; verify installed version against the relevant advisories
Jakarta Mail API PluginSMTP command injectionFixed release identified
Java runtimeJava 21 support end-date warningMaintenance and compatibility planning required; not itself a vulnerability
Built-in Jenkins nodeSecurity and isolation concernConfiguration change recommended; not itself a vulnerability

What about vulnerabilities that still have no fix?

The original screenshot explicitly labelled the Gradle Plugin and GitHub Branch Source Plugin findings as having no fix available. However, subsequent official advisories identify fixes for the issues discussed above. Therefore, it would be misleading to describe those two vulnerabilities as currently unpatched solely on the basis of the screenshot.

Likewise, the truncated Jakarta Mail API entry should not be classified as having an unknown current fix status when the official advisory identifies a fixed release.

For any issue where the exact advisory or installed version cannot be established, the appropriate classification is remediation status not yet verified, rather than no fix exists.

10. Other administrative warnings

Two additional messages on the dashboard deserve attention, although they are not vulnerability advisories.

Java 21 end-of-life notice

The dashboard warns that Java 21 support will end on or after 30 September 2027. This does not mean Java 21 is already unsupported. It means administrators should plan for future runtime compatibility and review Jenkins' supported Java versions before upgrading.

Builds running on the built-in node

Jenkins recommends setting the number of executors on the built-in node to zero. The controller should ideally manage Jenkins itself rather than execute untrusted or resource-intensive builds.

Running builds on separate agents improves isolation and reduces the risk that a compromised build can affect the controller. This is an architectural security recommendation, not a report that an attack has occurred.

11. A practical remediation checklist

For an administrator reviewing these warnings, I recommend the following sequence.

  1. Back up Jenkins. Preserve $JENKINS_HOME, configuration files, job definitions, and required credentials using an appropriate secure backup procedure.

  2. Record the environment. Capture the Jenkins core version, Java runtime, installed plugin versions, enabled security realm, and relevant authentication configuration.

  3. Review official advisories. Use the Jenkins Security Advisories index to identify the affected and fixed versions.

  4. Upgrade Jenkins core. Choose a supported security-fixed release and follow the documented upgrade path.

  5. Update affected plugins. Check plugin compatibility with the selected core release before updating, and pay particular attention to LDAP, Gradle, GitHub Branch Source, Pipeline: Groovy, EDD SA API, and Jakarta Mail API.

  6. Address unresolved issues. If a component has no available fix, assess whether it is necessary, restrict its use, apply documented mitigations, or disable or uninstall it where appropriate.

  7. Review access controls. Restrict administrative privileges, script approval, job configuration, credential access, and access to Jenkins endpoints.

  8. Separate build execution. Where feasible, run builds on appropriately isolated agents instead of the built-in node.

  9. Verify after updating. Restart Jenkins when required, confirm jobs and agents still work, and revisit the security warnings to verify that the affected versions have actually changed.

  10. Document the result. Record the versions installed, advisories addressed, mitigations applied, and any remaining accepted risks.

Do not assume that clicking an update button resolves every warning. Some findings require a core upgrade, some require a plugin update, and others require configuration changes.

Conclusion

My Jenkins dashboard illustrates an important aspect of maintaining a CI/CD environment: installing Jenkins is only the beginning. Core releases, plugin dependencies, access controls, and the architecture of build execution all contribute to the security of the installation.

The most useful response to a large number of warnings is not to dismiss them or to update everything without preparation. It is to identify the affected components, consult the authoritative security advisories, determine which fixes are available, and apply changes in a controlled and verifiable manner.

A security dashboard is most valuable when its warnings lead to documented action and follow-up verification.

References

Editorial note: This article documents the warnings visible in the supplied screenshots and selected official advisories. It is not a penetration test or a complete audit of the Jenkins installation. Confirm the exact installed plugin versions and their corresponding advisories before treating any vulnerability as resolved.

Saturday, July 18, 2026

CUDA Hello World - Gain Experience of 10 Years

If you already know the fundamentals from your earlier work with Nsight Eclipse. A lot has changed since then, and your current setup is far better going by current standards.

The IDE situation in 2026

About 10 years back, you needed Nsight Eclipse because it was the only CUDA-aware IDE. That's no longer true. VS Code is now the go-to for CUDA development — and you already have it installed 

Nsight Eclipse is Linux-only and essentially deprecated for Windows. On Windows, NVIDIA moved to Nsight Visual Studio Edition (integrates into Visual Studio) or the standalone Nsight Systems/Compute profilers — which you already have Nsight Compute installed.

Open a terminal and run:

cmd
nvcc --version

Already confirmed ✓. Now try compiling a tiny .cu file:

cuda
// hello.cu
#include <stdio.h>

__global__ void hello() {
    printf("Hello from thread %d, block %d\n", threadIdx.x, blockIdx.x);
}

int main() {
    hello<<<2, 4>>>();
    cudaDeviceSynchronize();
    return 0;
}

Save it anywhere and compile with:

cmd
    nvcc hello.cu -o hello.exe
    hello.exe

If you see 8 lines printing (2 blocks × 4 threads), your entire chain — driver, CUDA toolkit, nvcc, and GPU — is working end to end. That's your "Hello World" moment, much more meaningful than the bit-reverse template because you'll understand exactly why 8 lines print. BIT REVERSE TEMPLATE DEMO


What's different from 2016

2016 (your 410M)2026 (your GTX 1650)
CUDA 5.5, CC 2.1        CUDA 12.2, CC 7.5
Nsight Eclipse on Ubuntu        VS Code + nvcc on Windows
No Tensor Cores        Tensor Cores available
~192 CUDA cores        896 CUDA cores
No printf in kernels easily     printf from device works natively

The printf inside the kernel above would not have worked cleanly on your old 410M — it's a nice demonstration that your new hardware is a proper leap forward.

C:\Users\usrname\OneDrive\Documents\GitHub\LearningC>nvcc helloWorld.cu -o helloWorld.exe

helloWorld.cu

tmpxft_00001d74_00000000-10_helloWorld.cudafe1.cpp

   Creating library helloWorld.lib and object helloWorld.exp


C:\Users\usrname\OneDrive\Documents\GitHub\LearningC>helloWorld.exe

Hello from thread 0, block 0

Hello from thread 1, block 0

Hello from thread 2, block 0

Hello from thread 3, block 0

Hello from thread 0, block 1

Hello from thread 1, block 1

Hello from thread 2, block 1

Hello from thread 3, block 1


Let's Go!!

got 8 hello messages

That's your GPU running code you wrote. 8 lines = 2 blocks × 4 threads, all executing in parallel on the GTX 1650.

Notice what just happened in that launch syntax:

cuda
hello<<<2, 4>>>();

Those angle brackets are CUDA's extension to C++ — not standard C, not anything your MinGW or MSVC understands alone. Only nvcc parses them. The two numbers are:

  • 2 → number of blocks in the grid
  • 4 → number of threads per block

So total threads = 2 × 4 = 8. Each thread ran the same hello() function, but with a different threadIdx.x and blockIdx.x — that's how every thread knows who it is and what data to work on.

Now let's make it real — Lesson 2: Vector Addition

This is the "Hello World" of parallel computing that actually means something. You'll add two arrays of 1 million numbers simultaneously on the GPU.

This exercise teaches you the four fundamental steps every CUDA program ever written follows:

1. Allocate memory on GPU        (cudaMalloc)
2. Copy data CPU → GPU           (cudaMemcpy)
3. Launch kernel                 (kernel<<<blocks, threads>>>)
4. Copy result GPU → CPU         (cudaMemcpy back)

Create a new file vector_add.cu and type this out (don't copy-paste — typing it builds muscle memory):

#include <stdio.h>

#include <stdlib.h>


// DEVICE function — runs on GPU

// Each thread adds ONE pair of elements

__global__ void vectorAdd(float *a, float *b, float *c, int n) {

    // Calculate this thread's unique index

    int i = blockIdx.x * blockDim.x + threadIdx.x;


    // Guard: don't go out of bounds

    if (i < n) {

        c[i] = a[i] + b[i];

    }

}


int main() {

    int n = 1 << 20;          // 1,048,576 elements (1M)

    size_t bytes = n * sizeof(float);


    // --- HOST memory (CPU RAM) ---

    float *h_a = (float*)malloc(bytes);

    float *h_b = (float*)malloc(bytes);

    float *h_c = (float*)malloc(bytes);


    // Fill input arrays

    for (int i = 0; i < n; i++) {

        h_a[i] = (float)i;

        h_b[i] = (float)(i * 2);

    }


    // --- DEVICE memory (GPU VRAM) ---

    float *d_a, *d_b, *d_c;

    cudaMalloc(&d_a, bytes);

    cudaMalloc(&d_b, bytes);

    cudaMalloc(&d_c, bytes);


    // Step 2: Copy CPU → GPU

    cudaMemcpy(d_a, h_a, bytes, cudaMemcpyHostToDevice);

    cudaMemcpy(d_b, h_b, bytes, cudaMemcpyHostToDevice);


    // Step 3: Launch kernel

    int threads = 256;

    int blocks  = (n + threads - 1) / threads;   // ceiling division

    vectorAdd<<<blocks, threads>>>(d_a, d_b, d_c, n);


    // Step 4: Copy GPU → CPU

    cudaMemcpy(h_c, d_c, bytes, cudaMemcpyDeviceToHost);


    // Verify first 5 and last 5 results

    printf("First 5 results:\n");

    for (int i = 0; i < 5; i++)

        printf("  c[%d] = %.0f  (expected %.0f)\n", i, h_c[i], h_a[i] + h_b[i]);


    printf("Last 5 results:\n");

    for (int i = n-5; i < n; i++)

        printf("  c[%d] = %.0f  (expected %.0f)\n", i, h_c[i], h_a[i] + h_b[i]);


    // Cleanup

    cudaFree(d_a); cudaFree(d_b); cudaFree(d_c);

    free(h_a); free(h_b); free(h_c);


    printf("\nDone. %d elements added in parallel.\n", n);

    return 0;

}

Compile and run:

cmd
nvcc vector_add.cu -o vector_add.exe
vector_add.exe

The one line to understand deeply

cuda
int i = blockIdx.x * blockDim.x + threadIdx.x;

This is the most important line in all of CUDA. Every thread computes its own unique global index from three built-in variables:

VariableMeaningIn your launch
blockIdx.xWhich block am I in?0 to 4095
blockDim.xHow many threads per block?256
threadIdx.xWhich thread within my block?0 to 255

So thread 0 of block 3 gets index 3 * 256 + 0 = 768 — it adds a[768] + b[768]. Thread 1 of block 3 gets index 769. And so on. Every thread handles exactly one element, all simultaneously.

Run it and share the output — then we'll talk about why blocks = (n + threads - 1) / threads and what happens if you skip the if (i < n) guard.

Output:

C:\Users\usrname\OneDrive\Documents\GitHub\LearningC>nvcc vector_add.cu -o vector_add.exe

vector_add.cu

tmpxft_00003078_00000000-10_vector_add.cudafe1.cpp

   Creating library vector_add.lib and object vector_add.exp

C:\Users\usrname\OneDrive\Documents\GitHub\LearningC>vector_add.exe

First 5 results:

  c[0] = 0  (expected 0)

  c[1] = 3  (expected 3)

  c[2] = 6  (expected 6)

  c[3] = 9  (expected 9)

  c[4] = 12  (expected 12)

Last 5 results:

  c[1048571] = 3145713  (expected 3145713)

  c[1048572] = 3145716  (expected 3145716)

  c[1048573] = 3145719  (expected 3145719)

  c[1048574] = 3145722  (expected 3145722)

  c[1048575] = 3145725  (expected 3145725)

Done. 1048576 elements added in parallel.

Friday, June 12, 2026

Building an IoT Bus Passenger Counter in Public Transport

 

Building an IoT Passenger Counter

ESP32 · MQTT · Express.js · React

A complete step-by-step guide for Windows

Overview

This guide walks you through building a real-time passenger counter using a single IR sensor connected to an ESP32 microcontroller. Sensor events are published over WiFi using the MQTT protocol to a Mosquitto broker running on Windows. An Express.js backend subscribes to the broker and pushes live updates to a React dashboard via WebSocket.

 

Component

Role

ESP32 + IR sensor

Detects beam breaks, publishes count

Mosquitto broker

MQTT message router (Windows service)

Express.js server

Subscribes to MQTT, serves REST + WebSocket

React (Vite)

Live dashboard — updates without page refresh

 

Part 1 — USB Driver Installation

The ESP32 communicates with your PC over USB via a USB-to-UART bridge chip. You must install the correct driver before Windows can detect the board.

 

Step 1 — Identify the bridge chip

Look at your ESP32 board near the USB connector. The chip will be labelled with one of the following:

 

Chip marking

Driver needed

CP2102 or CP2104

Silicon Labs CP210x VCP

CH340 or CH341

WCH CH340 driver

FT232 or FT231

FTDI VCP driver

 

Step 2 — Download and install the Silicon Labs CP210x driver

1.     Open your browser and go to: www.silabs.com/developers/usb-to-uart-bridge-vcp-drivers

2.     Under Downloads, select CP210x Windows Drivers and download the ZIP file.

3.     Extract the ZIP. Right-click CP210xVCPInstaller_x64.exe and choose Run as administrator.

4.     Follow the installer prompts and click Finish.

5.     Plug in your ESP32 via USB.

6.     Open Device Manager (Win + X → Device Manager). You should see Silicon Labs CP210x USB to UART Bridge (COMx) under Ports (COM & LPT).

7.     Note the COM port number — you will need it in Arduino IDE.

 

⚠  If your board uses a CH340 chip instead, download the driver from: www.wch-ic.com/downloads/CH341SER_EXE.html — the installation steps are identical.

 

Part 2 — Arduino IDE Setup

Step 1 — Download and install Arduino IDE

8.     Go to www.arduino.cc/en/software

9.     Download the Windows installer (.exe).

10.  Run the installer. Accept the license, keep default options, click Install.

11.  Launch Arduino IDE once installation is complete.

 

Step 2 — Add ESP32 board support

12.  In Arduino IDE go to File → Preferences.

13.  Find the Additional Board Manager URLs field and paste:

 

https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json

 

14.  Click OK.

15.  Go to Tools → Board → Boards Manager.

16.  Search for esp32 and install the package by Espressif Systems.

17.  Once installed, go to Tools → Board → ESP32 Arduino → ESP32 Dev Module.

18.  Set Tools → Port to the COM port you noted during driver installation.

19.  Set Tools → Upload Speed to 115200 for reliable uploads.

 

ℹ  If upload fails, hold the BOOT button on the ESP32 as soon as you see Connecting... in the Arduino IDE console, then release once uploading begins.

 

Step 3 — Install required libraries

Go to Sketch → Include Library → Manage Libraries and install each of the following:

 

Library

Purpose

PubSubClient by Nick O'Leary

MQTT publish and subscribe for ESP32

ArduinoJson by Benoit Blanchon

JSON serialization for MQTT payloads

 

Search the library name, click the result, then click Install.

 

Part 3 — IR Sensor Wiring

Components

•        ESP32 Dev Module

•        1× IR obstacle sensor module (with OUT, VCC, GND pins)

•        Breadboard and male-to-male jumper wires

 

Connections

IR sensor pin

Connect to ESP32

VCC

3.3V or 5V (check your module — most accept both)

GND

GND

OUT

GPIO 34

 

ℹ  GPIO 34 is input-only on the ESP32 — it has no internal pull-up. If your readings are noisy, wire a 10kΩ resistor between GPIO 34 and 3.3V.

 

Part 4 — ESP32 Firmware

Create a new sketch in Arduino IDE (File → New), paste the code below, update your WiFi credentials and broker IP, then upload.

 

Find your PC IP address

Open Command Prompt and run:

 

ipconfig

 

Look for IPv4 Address under your WiFi adapter. Example: 192.168.1.105. Use this as mqttServer in the sketch.

 

sketch.ino — paste into Arduino IDE

#include <WiFi.h>

#include <PubSubClient.h>

 

#define IR_PIN 34

 

const char* ssid       = "YOUR_WIFI_SSID";

const char* password   = "YOUR_WIFI_PASSWORD";

const char* mqttServer = "192.168.1.105";  // your PC IPv4

const int   mqttPort   = 1883;

const char* topic      = "bus/passengers";

 

WiFiClient   wifiClient;

PubSubClient mqtt(wifiClient);

 

int  obstacleCount = 0;

bool lastState     = false;

 

void setup() {

  Serial.begin(115200);

  pinMode(IR_PIN, INPUT);

 

  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) delay(500);

  Serial.println("WiFi connected");

 

  mqtt.setServer(mqttServer, mqttPort);

  while (!mqtt.connected()) {

    mqtt.connect("esp32-bus");

    delay(500);

  }

  Serial.println("MQTT connected");

}

 

void loop() {

  mqtt.loop();

 

  bool beamBroken = digitalRead(IR_PIN) == LOW;

 

  // Rising edge detection — count only on the moment beam first breaks

  if (beamBroken && !lastState) {

    obstacleCount++;

    Serial.print("Obstacle count: ");

    Serial.println(obstacleCount);

 

    String payload = "{\"count\":" + String(obstacleCount)

                   + ",\"busId\":\"BUS_01\"}";

    mqtt.publish(topic, payload.c_str());

  }

 

  lastState = beamBroken;

  delay(50);  // debounce

}

 

After uploading, open Tools → Serial Monitor at 115200 baud. You should see WiFi connected followed by MQTT connected. Wave your hand in front of the IR sensor — the count increments and is published to bus/passengers.

 

Part 5 — Mosquitto MQTT Broker on Windows

Step 1 — Install Mosquitto

20.  Go to mosquitto.org/download

21.  Download the Windows installer (.exe).

22.  Run the installer with default options.

 

Step 2 — Create a config file

Create the following folder and config file:

 

C:\mosquitto\mosquitto.conf

 

Paste this content into the file:

 

# Network

listener 1883

protocol mqtt

 

# Allow anonymous connections (fine for local dev)

allow_anonymous true

 

# Logging

log_type all

log_dest file C:\mosquitto\mosquitto.log

log_timestamp true

 

# Persistence

persistence true

persistence_location C:\mosquitto\data\

 

Create the data folder:

 

md C:\mosquitto\data

 

Step 3 — Open port 1883 in Windows Firewall

netsh advfirewall firewall add rule name="Mosquitto MQTT" ^

  dir=in action=allow protocol=TCP localport=1883

 

Step 4 — Stop any existing Mosquitto service

net stop mosquitto

 

Step 5 — Run Mosquitto with your config

cd "C:\Program Files\mosquitto"

mosquitto.exe -c C:\mosquitto\mosquitto.conf -v

 

You should see: Opening ipv4 listen socket on port 1883.

 

Step 6 — Verify the broker

Open a second Command Prompt:

 

mosquitto_sub.exe -h localhost -t "bus/passengers" -v

 

Open a third Command Prompt and publish a test message:

 

mosquitto_pub.exe -h localhost -t "bus/passengers" -m "{\"count\":1}"

 

The first terminal should display the message. Broker is confirmed working.

 

ℹ  MQTT Explorer (free GUI at mqtt-explorer.com) is highly recommended — connect it to localhost:1883 to visually inspect all topics and messages without using the terminal.

 

Part 6 — Express.js Backend

Step 1 — Create the project (nodejs needs to be installed in the system)

md bus-counter && cd bus-counter

md server && cd server

npm init -y

npm install express mqtt socket.io cors

 

Step 2 — Create server.js

server/server.js

const express    = require('express');

const http       = require('http');

const { Server } = require('socket.io');

const mqtt       = require('mqtt');

const cors       = require('cors');

 

const app    = express();

const server = http.createServer(app);

const io     = new Server(server, { cors: { origin: '*' } });

 

app.use(cors());

app.use(express.json());

 

let passengerCount = 0;

let history = [];

 

const mqttClient = mqtt.connect('mqtt://localhost:1883');

 

mqttClient.on('connect', () => {

  console.log('MQTT connected');

  mqttClient.subscribe('bus/passengers');

});

 

mqttClient.on('message', (topic, message) => {

  const data = JSON.parse(message.toString());

  passengerCount = data.count;

 

  const entry = { ...data, timestamp: new Date().toISOString() };

  history.push(entry);

  if (history.length > 100) history.shift();

 

  console.log('Received:', entry);

  io.emit('passengerUpdate', entry);

});

 

app.get('/passengers', (req, res) => {

  res.json({ count: passengerCount, busId: 'BUS_01' });

});

 

app.get('/history', (req, res) => {

  res.json(history);

});

 

server.listen(3001, () =>

  console.log('Server running on http://localhost:3001')

);

 

Step 3 — Run the server

node server.js

 

You should see: MQTT connected followed by Server running on http://localhost:3001.

 

Test the REST endpoint by opening http://localhost:3001/passengers in your browser.

 

Part 7 — React Dashboard

Step 1 — Create the Vite + React project

cd ..

npm create vite@latest client -- --template react

cd client

npm install

npm install socket.io-client

 

Step 2 — Replace src/App.jsx

client/src/App.jsx

import { useEffect, useState } from "react";

import { io } from "socket.io-client";

 

const socket = io("http://localhost:3001");

const MAX_CAPACITY = 40;

 

export default function App() {

  const [count, setCount]     = useState(0);

  const [history, setHistory] = useState([]);

  const [status, setStatus]   = useState("connecting");

 

  useEffect(() => {

    fetch("http://localhost:3001/passengers")

      .then(r => r.json())

      .then(d => setCount(d.count));

 

    fetch("http://localhost:3001/history")

      .then(r => r.json())

      .then(setHistory);

 

    socket.on("connect",    () => setStatus("live"));

    socket.on("disconnect", () => setStatus("disconnected"));

    socket.on("passengerUpdate", (data) => {

      setCount(data.count);

      setHistory(prev => [...prev.slice(-99), data]);

    });

 

    return () => socket.off("passengerUpdate");

  }, []);

 

  const pct      = Math.round((count / MAX_CAPACITY) * 100);

  const barColor = pct > 90 ? "#E24B4A" : pct > 70 ? "#EF9F27" : "#1D9E75";

 

  return (

    <div style={{ fontFamily: "sans-serif", maxWidth: 600,

                  margin: "2rem auto", padding: "0 1rem" }}>

 

      <div style={{ display: "flex", justifyContent: "space-between",

                    alignItems: "center", marginBottom: "1.5rem" }}>

        <h1 style={{ fontSize: 20, fontWeight: 500, margin: 0 }}>

          Bus passenger counter

        </h1>

        <span style={{

          fontSize: 12, padding: "4px 10px", borderRadius: 20,

          background: status === "live" ? "#EAF3DE" : "#FCEBEB",

          color:      status === "live" ? "#3B6D11" : "#A32D2D"

        }}>

          {status === "live" ? "● Live" : "○ Disconnected"}

        </span>

      </div>

 

      <div style={{ background: "#f5f5f3", borderRadius: 12,

                    padding: "1.5rem", marginBottom: "1rem", textAlign: "center" }}>

        <p style={{ fontSize: 13, color: "#888", margin: "0 0 8px" }}>

          Passengers on board

        </p>

        <p style={{ fontSize: 64, fontWeight: 500, margin: "0 0 16px",

                    lineHeight: 1 }}>{count}</p>

        <p style={{ fontSize: 13, color: "#888", margin: "0 0 10px" }}>

          of {MAX_CAPACITY} capacity ({pct}%)

        </p>

        <div style={{ background: "#ddd", borderRadius: 6,

                      height: 10, overflow: "hidden" }}>

          <div style={{ width: `${pct}%`, height: "100%",

                        background: barColor, borderRadius: 6,

                        transition: "width 0.4s, background 0.4s" }}/>

        </div>

      </div>

 

      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr 1fr",

                    gap: 10, marginBottom: "1.5rem" }}>

        {[

          { label: "Status",    value: pct > 90 ? "Full" : pct > 70 ? "Busy" : "Normal" },

          { label: "IR events", value: history.length },

          { label: "Available", value: Math.max(0, MAX_CAPACITY - count) },

        ].map(({ label, value }) => (

          <div key={label} style={{ background: "#f5f5f3",

                                    borderRadius: 8, padding: "0.75rem 1rem" }}>

            <p style={{ fontSize: 12, color: "#888", margin: "0 0 4px" }}>{label}</p>

            <p style={{ fontSize: 20, fontWeight: 500, margin: 0 }}>{value}</p>

          </div>

        ))}

      </div>

 

      <div style={{ border: "0.5px solid #ddd", borderRadius: 10, overflow: "hidden" }}>

        <p style={{ fontSize: 13, fontWeight: 500, padding: "10px 14px",

                    margin: 0, borderBottom: "0.5px solid #ddd" }}>

          Recent IR events

        </p>

        {history.length === 0 && (

          <p style={{ fontSize: 13, color: "#888",

                      padding: "12px 14px", margin: 0 }}>

            Waiting for sensor data...

          </p>

        )}

        {[...history].reverse().slice(0, 8).map((h, i) => (

          <div key={i} style={{ display: "flex", justifyContent: "space-between",

                               padding: "8px 14px",

                               borderBottom: "0.5px solid #eee", fontSize: 13 }}>

            <span>Count: <strong>{h.count}</strong></span>

            <span style={{ color: "#888" }}>

              {new Date(h.timestamp).toLocaleTimeString()}

            </span>

          </div>

        ))}

      </div>

    </div>

  );

}

 

Step 3 — Run the React app

npm run dev

 

Open http://localhost:5173 in your browser. The dashboard connects automatically and updates live whenever the IR sensor fires.

 

Part 8 — Running Everything Together

Open three separate Command Prompt windows and run each command:

 

Terminal

Command

Terminal 1 — MQTT broker

cd "C:\Program Files\mosquitto" && mosquitto.exe -c C:\mosquitto\mosquitto.conf -v

Terminal 2 — Express server

cd bus-counter\server && node server.js

Terminal 3 — React app

cd bus-counter\client && npm run dev

 

Then open http://localhost:5173 in your browser. Wave your hand in front of the IR sensor — the count increments live on the dashboard with no page refresh.

 Pics:




Troubleshooting

Problem

Fix

ESP32 not detected in Device Manager

Install the correct USB driver (CP210x or CH340). Try a different USB cable — many are charge-only with no data lines.

Upload fails with exit status 74

Hold the BOOT button on the ESP32 while clicking Upload. Release once you see progress percentages.

MQTT broker port already in use

Run: net stop mosquitto — a background service is already running on 1883.

ESP32 connects to WiFi but not MQTT

Check Windows Firewall — port 1883 must be open. Verify both devices are on the same WiFi network.

React dashboard shows Disconnected

Ensure Express server is running on port 3001. Check browser console for CORS errors.

Count increments multiple times per pass

Increase the delay(50) debounce value in the sketch to delay(150) or higher.