An Android IoT application for real-time pesticide residue detection on agricultural produce. PestiSafe connects to an electrochemical sensor over a local WiFi network, converts raw voltage readings into pesticide concentration values (ppm) via a calibration curve, and compares results against FAO Codex Maximum Residue Limits (MRLs) to give a clear safe / unsafe verdict on sampled produce.
- Overview
- Features
- Architecture
- Screen Flow
- Database Schema
- Setup & Requirements
- Dependencies
- How It Works
- Project Structure
- Known Limitations
PestiSafe is designed for field use by agricultural inspectors, food safety auditors, or researchers who need a fast, portable way to test produce for pesticide contamination. The workflow is:
- Connect your Android device to the same WiFi network as the sensor.
- Fetch the latest pesticide & MRL database from the FAO Codex API.
- Select the pesticide you are testing for.
- Scan the local network to find the sensor device.
- Calibrate the sensor using known reference concentrations.
- Point the sensor at a food sample β view live concentration readings and an instant safety verdict.
- Export results as CSV, JSON, or Excel for reporting.
| Feature | Detail |
|---|---|
| Live sensor readings | Polls the IoT sensor over HTTP every 3 seconds and displays real-time voltage and concentration |
| Calibration engine | Collects voltage readings at 8 known concentrations, fits a least-squares linear regression, and validates with RΒ² β₯ 0.9 |
| FAO MRL database | Fetches and caches the complete FAO Codex pesticide + Maximum Residue Limit dataset on-device |
| Safety verdict | Compares live concentration against the FAO MRL for the selected pesticide-commodity pair; displays a clear SAFE β
or UNSAFE |
| IP Scanner | Scans the local /24 subnet to discover sensor devices automatically |
| Data export | Export all captured readings as CSV, JSON, or Excel (.xlsx) and share via Android's standard file share sheet |
| User accounts | Local account system with BCrypt-hashed passwords and a DOB-verified password reset flow |
| Secure networking | Cleartext HTTP restricted to LAN IP ranges only (FAO API uses HTTPS) |
PestiSafe follows Modern Android Architecture with a clean separation of concerns:
UI Layer β Jetpack Compose + Material Design 3
State Management β ViewModel + MutableStateFlow / LiveData
Data Layer β Room Database + Repository pattern
Async β Kotlin Coroutines + SupervisorJob
Navigation β Jetpack Navigation Compose
- Single ViewModel (
MainViewModel) acts as the central state owner for sensor data, calibration coefficients, and navigation state. - Repository pattern wraps all DAO access so the ViewModel never talks to Room directly.
- Reactive UI β all DAO queries return
FloworLiveData, so the chart and readings update automatically when new data is captured. - Side-effect safety β all navigation calls and state mutations are performed inside
LaunchedEffectblocks, never directly during Compose's composition phase.
Login / Sign-Up
β
βΌ
Main (Connect Screen)
β’ Check WiFi connection
β’ Fetch FAO pesticide + MRL dataset
β
βΌ
Pesticide Selection
β’ Choose target pesticide from FAO list
β
βΌ
IP Scanner
β’ Scan local /24 subnet (254 hosts concurrently)
β’ Select sensor device IP
β
βΌ
Calibration
β’ Record voltage at 8 known concentrations
β’ Fit linear regression (requires RΒ² β₯ 0.9)
β
βΌ
Home (Live Monitoring)
β’ Real-time voltage + concentration display
β’ Line chart of all captured readings
β’ Select pesticide + commodity β view FAO MRL
β’ SAFE / UNSAFE verdict
β’ "Capture Reading" button β saves to database
β’ Export data (CSV / JSON / Excel)
A dropdown menu in the top app bar allows jumping between any screen at any time.
Five Room entities:
| Column | Type | Notes |
|---|---|---|
| id | Int (PK, autoGen) | |
| name | String | Display name |
| username | String | Unique β enforced by index |
| String | ||
| password | String | BCrypt hashed |
| dob | String | Used for password reset verification |
| Column | Type | Notes |
|---|---|---|
| id | Int (PK) | FAO Codex pesticide ID |
| name | String | English name from FAO API |
| Column | Type | Notes |
|---|---|---|
| id | Int (PK, autoGen) | |
| name | String | Crop / food product name |
| Column | Type | Notes |
|---|---|---|
| mrlID | Int (PK, autoGen) | |
| pesticideID | Int (FK β Pesticide) | CASCADE delete |
| commodityID | Int (FK β Commodity) | CASCADE delete |
| mrl | Double | Maximum Residue Limit in ppm |
| Column | Type | Notes |
|---|---|---|
| id | Int (PK, autoGen) | |
| voltage | Double | Raw sensor reading (V) |
| concentration | Double | Calculated concentration (ppm) |
- Android Studio Hedgehog or newer
- Android device or emulator running Android 7.0+ (API 24+)
- A compatible electrochemical sensor device on the same WiFi network
- Clone the repository:
git clone https://github.com/Shash976/wifi-data-app.git cd wifi-data-app - Open in Android Studio.
- Let Gradle sync and download dependencies.
- Run on a device or emulator (
Run > Run 'app').
The app requests the following at runtime:
| Permission | Reason |
|---|---|
INTERNET |
FAO API calls + sensor HTTP polling |
ACCESS_WIFI_STATE |
Check WiFi connectivity before connecting |
ACCESS_NETWORK_STATE |
Network availability checks |
READ/WRITE_EXTERNAL_STORAGE |
File export on Android 9 and below (not needed on API 29+) |
Cleartext HTTP is allowed only for local LAN IP ranges (192.168.x.x, 10.x.x.x, 172.16.x.x) via a Network Security Config. All external traffic (including FAO API) uses HTTPS.
| Library | Version | Purpose |
|---|---|---|
| Jetpack Compose BOM | 2025.06.00 | Declarative UI framework |
| Material Design 3 | β | UI components and theming |
| Room | 2.7.1 | Local SQLite ORM |
| Navigation Compose | 2.9.0 | Screen routing |
| Lifecycle ViewModel | 2.9.1 | State management |
| Kotlin Coroutines | 1.8.0 | Async operations |
| Vico Charts | 2.0.0-alpha.19 | Line chart rendering |
| Gson | 2.10.1 | FAO API JSON deserialization |
BCrypt (jbcrypt) |
0.9.0 | Password hashing |
| Apache POI OOXML | 5.2.3 | Excel (.xlsx) export |
| WorkManager | 2.10.1 | Background task scheduling (future use) |
SDK versions: minSdk = 24, targetSdk = 35
The sensor produces a voltage proportional to pesticide concentration. Calibration establishes the mapping:
Concentration (ppm) = (Voltage - Intercept) / Slope
The app steps through 8 reference concentrations [1.0, 10.0, 5.0, 7.5, 6.0, 2.5, 4.0, 1.25] ppm. At each step, the user places the sensor in a reference solution and captures the voltage. Once β₯ 3 points are collected, least-squares linear regression is fitted. Calibration is accepted only when RΒ² β₯ 0.9.
On the Connect screen, the app fetches from two FAO Codex endpoints:
- Pesticide list:
https://www.fao.org/jsoncodexpest/jsonrequest/pesticides/index.html - MRL details per pesticide:
https://www.fao.org/jsoncodexpest/jsonrequest/pesticides/details.html?id={id}
Results are cached in the local Room database and deduped on subsequent fetches.
Once a pesticide and commodity are selected on the Home screen:
- The MRL for that pair is retrieved from the local database.
- The current concentration (converted from live sensor voltage using the calibration coefficients) is compared to the MRL.
- If
concentration > MRLβ UNSAFE (red warning). - If
concentration β€ MRLβ SAFE (green confirmation).
Live readings update the display continuously but are not auto-saved. Tap "Capture Reading" to intentionally commit a reading to the database. Captured readings appear in the chart and can be exported:
- CSV β comma-separated with headers
- JSON β Gson-serialized array
- Excel β
.xlsxworkbook with column headers and auto-sized columns (via Apache POI)
Files are named {username}_{pesticide}_{commodity}_data.{ext} and shared via Android's standard share sheet.
app/src/main/java/com/example/pestisafe/
βββ MainActivity.kt # Entry point, Navigation host, Scaffold
βββ MainViewModel.kt # Central state, sensor polling, FAO API, calibration math
βββ Database.kt # Room entities, DAOs, Repository
βββ Routes.kt # Navigation route enum
β
βββ LoginSignUp.kt # Auth screen (login, sign-up, password reset)
βββ ConnectScreen.kt # WiFi check + FAO data fetch
βββ PesticideSelectionScreen.kt # Pesticide picker dropdown
βββ ScanScreen.kt # LAN IP scanner
βββ CalibrationScreen.kt # Sensor calibration wizard
βββ HomeScreen.kt # Live monitoring, MRL verdict, export
β
βββ MathFuncs.kt # Linear regression, RΒ² calculation
βββ Chart.kt # Vico chart configuration
βββ Deserializers.kt # Gson deserializers for FAO API JSON
βββ DownloadFuncs.kt # CSV / JSON / Excel export + file sharing
βββ Formats.kt # Export format enum
β
βββ ui/theme/
βββ Theme.kt # Material3 theme setup
βββ Color.kt # Color palette
βββ Type.kt # Typography
- Offline mode β The app requires WiFi throughout: for the FAO API fetch on first use and for sensor communication. No offline fallback exists once data is cached.
- Single sensor β The app connects to one sensor device at a time.
- HTTP sensor protocol β Sensor devices communicate over plain HTTP (acceptable for LAN-only use but not suitable for untrusted networks).
- Legacy v1 code β The
v1/package contains an older Activity-based implementation. It is not used by the current Compose app and will be removed in a future cleanup.
This project is developed as part of an academic research project. All rights reserved.