0% found this document useful (0 votes)
5 views

Manual Guide

Uploaded by

Arwan
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
5 views

Manual Guide

Uploaded by

Arwan
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 22

PENDAHULUAN

LeafyNourish Merupakan sebuah prototipe sistem berbasis IoT yang dapat

mengukur kadar nutrisi pada tanah seperti nitrogen, fosfor, kalium, dan pH.

Selain itu, LeafyNourish juga dapat memantau suhu dan kelembapan sekitar

tanah. Prototipes sistem ini berbasis ESP32 dan terhubung ke firebase

sehingga data-data sensor dapat dipantau menggunakan aplikasi android

secara real-time. Pada aplikasi yang dikembangkan, LeafyNourish juga dapat

melakukan rekomendasi berdasarkan data-data dari sensor.

KOMPONEN PROTOTYPE
PETUNJUK PENGOPERASIAN

Untuk menggunakan prototipe, Power Adapter terlebih dahulu dipasang ke

prototipe alat. Selanjunya untuk mengukur kadar nutrisi tanah, Sensor NPK

dan pH Tanah ditancapkan ke Tanah yang ingin diukur kadar nutrisi nya.

Kadar nutrisi selanjutnya dapat dipantau pada Aplikasi Android

LeafyNourish. Jika pengguna ingin mengetahui tanaman yang cocok untuk

ditanam pada tanah, pengguna dapat menenkan tombol Rekomendasi pada

halaman utama. Pengguna kemudian harus menunggu selama sepuluh detik

untuk aplikasi menampilkan hasil rekomendasi beserta data nutrisi, suhu dan

kelembapan yang digunakan.


SOURCE CODE

ARDUINO

#include <WiFi.h>
#include <SoftwareSerial.h>
#include <Wire.h>
#include <FirebaseESP32.h>
#include "addons/TokenHelper.h"
#include "addons/RTDBHelper.h"
#include "DHT.h"

#define TX_PIN 26 //DI


#define RX_PIN 27 //R0
#define RE_DE 33 // Connect RE terminal with 32 of ESP

//sensor dht11
#define DHTPIN 2
#define DHTTYPE DHT11

#define DMSpin 13 // pin output untuk DMS


#define adcPin 34 // pin input sensor pH tanah

//variabel
int ADC;
float lastReading;
float pH;

const byte nitro[] = {0x01, 0x03, 0x00, 0x1e, 0x00, 0x01, 0xe4, 0x0c};
const byte phos[] = {0x01, 0x03, 0x00, 0x1f, 0x00, 0x01, 0xb5, 0xcc};
const byte pota[] = {0x01, 0x03, 0x00, 0x20, 0x00, 0x01, 0x85, 0xc0};

byte values[11];
SoftwareSerial mod(RX_PIN, TX_PIN); //RI_2, DI 3

//Wifi
const char* ssid = "Internet Berbayar ya Guys";
const char* password = "rorororo";

//Firebase
#define DATABASE_URL "https://leafynourish-default-rtdb.asia-
southeast1.firebasedatabase.app/"
#define API_KEY "AIzaSyDrfmQbuKuiWFyRkYcm6Zwkos8Z5V-Revo"

//Define Firebase Data object


FirebaseData firebaseData;

FirebaseAuth auth;
FirebaseConfig config;

unsigned long sendDataPrevMillis = 0;

bool signupOK = false;

DHT dht(DHTPIN, DHTTYPE);

void setup() {
Serial.begin(115200);
mod.begin(4800);
pinMode(RE_DE, OUTPUT);

dht.begin();

Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);

while (WiFi.status() != WL_CONNECTED) {


delay(500);
Serial.print(".");
delay(300);
}
// Print local IP address and start web server
Serial.println();
Serial.print("Connected with IP: ");
Serial.println(WiFi.localIP());
Serial.println();

config.api_key = API_KEY;
config.database_url = DATABASE_URL;

if (Firebase.signUp(&config, &auth, "", "")) {


Serial.println("Firebase Status Ok");
signupOK = true;
}
else {
Serial.printf("%s\n", config.signer.signupError.message.c_str());
}

config.token_status_callback = tokenStatusCallback; //see


addons/TokenHelper.h

Firebase.begin(&config, &auth);
Firebase.reconnectWiFi(true);
analogReadResolution(10);
pinMode(DMSpin, OUTPUT);
digitalWrite(DMSpin, HIGH);
}

void loop() {
float temp = dht.readTemperature();
float hum = dht.readHumidity();

int val1, val2, val3;


val1 = nitrogen();
delay(250);
val2 = phosphorous();
delay(250);
val3 = potassium();
delay(250);

digitalWrite(DMSpin, LOW);
delay(5 * 1000);
ADC = analogRead(adcPin);
pH = (-0.0865 * ADC) + 7.9513;
if (pH != lastReading) {
lastReading = pH;
}

digitalWrite(DMSpin, HIGH);
delay(3 * 1000); // wait for DMS ready

if (Firebase.ready() && signupOK && (millis() - sendDataPrevMillis >


1000 || sendDataPrevMillis == 0)) {
Serial.print("Suhu : ");
Serial.println(temp);
Serial.print("Kelembapan : ");
Serial.println(hum);
Serial.print("Nitrogen : ");
Serial.println(val1);
Serial.print("Fosfor : ");
Serial.println(val2);
Serial.print("Kalium : ");
Serial.println(val3);
Serial.print("ADC : ");
Serial.print(ADC);
Serial.print("|| pH : ");
Serial.println(lastReading);

FirebaseJson data;

if (isnan(temp) || isnan(hum)) {
Serial.println("Gagal Mengirim data Suhu & Kelembapan || Cek
DHT11");
} else {
data.add("suhu", temp);
data.add("kelembapan", hum);
}
data.add("nitrogen", val1);
data.add("fosfor", val2);
data.add("kalium", val3);
data.add("ph", lastReading);

if (Firebase.pushJSON(firebaseData, "sensor_data", data)) {


Serial.println("Data berhasil dikirim ke Firebase!");
} else {
Serial.println("Gagal mengirim data ke Firebase.");
Serial.println("Alasan: " + firebaseData.errorReason());
}
}
Serial.println("");
Serial.println("");
Serial.println("");
delay(1000);
}

int nitrogen() {
digitalWrite(RE_DE, HIGH);
delay(100);
if (mod.write(nitro, sizeof(nitro)) == 8) {
mod.flush();
digitalWrite(RE_DE, LOW);
delay(200);
for (byte i = 0; i < 7; i++) {
//Serial.print(mod.read(),HEX);
values[i] = mod.read();
// Serial.print(values[i],HEX);
}
// Serial.println();
}
return values[3] << 8 | values[4];
}

int phosphorous() {
digitalWrite(RE_DE, HIGH);
delay(100);
if (mod.write(phos, sizeof(phos)) == 8) {
mod.flush();
digitalWrite(RE_DE, LOW);
delay(200);
for (byte i = 0; i < 7; i++) {
//Serial.print(mod.read(),HEX);
values[i] = mod.read();
// Serial.print(values[i],HEX);
}
// Serial.println();
}
return values[3] << 8 | values[4];
}

int potassium() {
digitalWrite(RE_DE, HIGH);
delay(100);
if (mod.write(pota, sizeof(pota)) == 8) {
mod.flush();
digitalWrite(RE_DE, LOW);
delay(200);
for (byte i = 0; i < 7; i++) {
//Serial.print(mod.read(),HEX);
values[i] = mod.read();
// Serial.print(values[i],HEX);
}
// Serial.println();
}
return values[3] << 8 | values[4];
}

ANDROID

MainActivity.Kt
class MainActivity : AppCompatActivity() {
private lateinit var databaseReference:
DatabaseReference
private lateinit var tvSuhuValue: TextView
private lateinit var tvHumValue: TextView
private lateinit var tvNitrogenValue: TextView
private lateinit var tvFosforValue: TextView
private lateinit var tvKaliumValue: TextView
private lateinit var tvPHValue: TextView
private lateinit var tvRecom: TextView

override fun onCreate(savedInstanceState: Bundle?) {


super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

tvSuhuValue = findViewById(R.id.tvSuhuValue)
tvHumValue = findViewById(R.id.tvHumValue)
tvNitrogenValue =
findViewById(R.id.tvNitrogenValue)
tvFosforValue = findViewById(R.id.tvFosforValue)
tvKaliumValue = findViewById(R.id.tvKaliumValue)
tvPHValue = findViewById(R.id.tvPHValue)
tvRecom = findViewById(R.id.tvRecom)
tvRecom.setOnClickListener {
val intent = Intent(this@MainActivity,
RecommendationActivity::class.java)
startActivity(intent)
}

databaseReference =
FirebaseDatabase.getInstance().reference.child("sensor_data
")

// Tambahkan listener untuk membaca data dari


Firebase Realtime Database
databaseReference.addChildEventListener(object :
ChildEventListener {
@SuppressLint("SetTextI18n")
override fun onChildAdded(snapshot:
DataSnapshot, previousChildName: String?) {
val suhu = snapshot.child("suhu").value
val kelembapan =
snapshot.child("kelembapan").value
val nitrogen =
snapshot.child("nitrogen").value
val fosfor = snapshot.child("fosfor").value
val kalium = snapshot.child("kalium").value
val ph = snapshot.child("ph").value as
Double

val roundePh = Math.round(ph * 10f) / 10f

tvSuhuValue.text = suhu?.toString() ?:
"0°C"
tvHumValue.text = kelembapan?.toString() ?:
"0%"
tvNitrogenValue.text = nitrogen?.toString()
?: "0"
tvFosforValue.text = fosfor?.toString() ?:
"0"
tvKaliumValue.text = kalium?.toString() ?:
"0"
tvPHValue.text = roundePh.toString() ?:
"0.0f"

setTextAndClickListener(tvSuhuValue,
"suhu")
setTextAndClickListener(tvHumValue,
"kelembapan")
setTextAndClickListener(tvNitrogenValue,
"nitrogen")
setTextAndClickListener(tvFosforValue,
"fosfor")
setTextAndClickListener(tvKaliumValue,
"kalium")
setTextAndClickListener(tvPHValue, "ph")
}

override fun onChildChanged(snapshot:


DataSnapshot, previousChildName: String?) {
TODO("Not yet implemented")
}

override fun onChildRemoved(snapshot:


DataSnapshot) {
TODO("Not yet implemented")
}

override fun onChildMoved(snapshot:


DataSnapshot, previousChildName: String?) {
TODO("Not yet implemented")
}

override fun onCancelled(error: DatabaseError)


{
TODO("Not yet implemented")
}
})
}

private fun setTextAndClickListener(textView: TextView,


childKey: String) {
textView.setOnClickListener {
val intent = Intent(this@MainActivity,
DetailActivity::class.java)
intent.putExtra("childKey", childKey)
startActivity(intent)
}
}
}

DetailActivity.Kt
package com.ananta.leafynourish

import android.graphics.Color
import android.graphics.drawable.GradientDrawable
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.github.mikephil.charting.charts.LineChart
import com.github.mikephil.charting.components.Description
import com.github.mikephil.charting.components.XAxis
import com.github.mikephil.charting.data.Entry
import com.github.mikephil.charting.data.LineData
import com.github.mikephil.charting.data.LineDataSet
import com.google.firebase.database.ChildEventListener
import com.google.firebase.database.DataSnapshot
import com.google.firebase.database.DatabaseError
import com.google.firebase.database.DatabaseReference
import com.google.firebase.database.FirebaseDatabase
import com.google.firebase.database.ValueEventListener
class DetailActivity : AppCompatActivity() {
private lateinit var lineChart: LineChart
private lateinit var valueEventListener:
ValueEventListener
private lateinit var databaseReference:
DatabaseReference

override fun onCreate(savedInstanceState: Bundle?) {


super.onCreate(savedInstanceState)
setContentView(R.layout.activity_detail)

lineChart = findViewById(R.id.lineChart)

// Ambil jenis data dari Intent


val childKey = intent.getStringExtra("childKey")

// Inisialisasi Firebase Realtime Database


databaseReference =
FirebaseDatabase.getInstance().reference.child("sensor_data
")

// Konfigurasi Chart
lineChart.description.isEnabled = false

val xAxis = lineChart.xAxis


xAxis.position = XAxis.XAxisPosition.BOTTOM
xAxis.setDrawGridLines(false)

val yAxisRight = lineChart.axisRight


yAxisRight.isEnabled = false

val yAxisLeft = lineChart.axisLeft


yAxisLeft.setDrawGridLines(false)

lineChart.legend.isEnabled = false

lineChart.animateX(500)

// Buat dataset dan tambahkan ke Chart


val dataset = LineDataSet(mutableListOf<Entry>(),
"Data")
dataset.setDrawCircles(true)
dataset.setDrawValues(true)
dataset.lineWidth = 2f
dataset.circleRadius = 6f
dataset.mode = LineDataSet.Mode.CUBIC_BEZIER
dataset.setCircleColor(Color.parseColor("#bdcf32"))
dataset.color = Color.parseColor("#bdcf32")
dataset.setDrawFilled(true)

val gradientDrawable = GradientDrawable(


GradientDrawable.Orientation.TOP_BOTTOM, //
Arah gradient
intArrayOf(Color.parseColor("#ede15b"),
Color.TRANSPARENT) // Warna gradient (mulai dari bawah)
)
dataset.fillDrawable = gradientDrawable

val lineData = LineData(dataset)


lineChart.data = lineData

// Tambahkan listener ke Firebase Realtime Database


databaseReference.addChildEventListener(object :
ChildEventListener{
override fun onChildAdded(snapshot:
DataSnapshot, previousChildName: String?) {
if (snapshot.exists()) {
val data: Number? = when (childKey) {
"suhu", "ph" ->
snapshot.child(childKey).getValue(Float::class.java)
"kelembapan", "nitrogen", "fosfor",
"kalium" ->
snapshot.child(childKey).getValue(Int::class.java)
else -> null
}

if (data != null) {
updateChart(data)
}
}
}

override fun onChildChanged(snapshot:


DataSnapshot, previousChildName: String?) {
TODO("Not yet implemented")
}

override fun onChildRemoved(snapshot:


DataSnapshot) {
TODO("Not yet implemented")
}

override fun onChildMoved(snapshot:


DataSnapshot, previousChildName: String?) {
TODO("Not yet implemented")
}

override fun onCancelled(error: DatabaseError)


{
TODO("Not yet implemented")
}

})
}

private fun updateChart(value: Number?) {


val data = lineChart.data
val dataset = data.getDataSetByIndex(0) as
LineDataSet

// Tambahkan data baru ke dataset


val entry = value?.let {
Entry(dataset.entryCount.toFloat(), it.toFloat()) }
dataset.addEntry(entry)

// Notifikasi bahwa data telah berubah


data.notifyDataChanged()
lineChart.notifyDataSetChanged()

// Scroll ke posisi terakhir


lineChart.setVisibleXRangeMaximum(10f) // Tampilkan
10 data terakhir
lineChart.moveViewToX(data.entryCount.toFloat())
}
}

RecommendationFragment.Kt
class RecommendationFragment : Fragment() {
private var startTimeMillis: Long = 0
private var endTimeMillis: Long = 0

private lateinit var tvSuhuData: TextView


private lateinit var tvHumData: TextView
private lateinit var tvNitrogenData: TextView
private lateinit var tvFosforData: TextView
private lateinit var tvKaliumData: TextView
private lateinit var tvPHData: TextView
private lateinit var tvResult: TextView
private lateinit var databaseReference:
DatabaseReference

private val url =


"https://leafynourish.vercel.app/predict"

override fun onCreateView(


inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
val view =
inflater.inflate(R.layout.fragment_recommendation,
container, false)

tvSuhuData = view.findViewById(R.id.tvSuhuData)
tvHumData = view.findViewById(R.id.tvHumData)
tvNitrogenData =
view.findViewById(R.id.tvNitrogenData)
tvFosforData = view.findViewById(R.id.tvFosforData)
tvKaliumData = view.findViewById(R.id.tvKaliumData)
tvPHData = view.findViewById(R.id.tvPHData)
tvResult = view.findViewById(R.id.tvResult)

databaseReference =
FirebaseDatabase.getInstance().reference.child("sensor_data
") // Ganti "data" dengan nama node di database Anda

return view
}

override fun onStart() {


super.onStart()

databaseReference.addListenerForSingleValueEvent(object :
ValueEventListener{
@SuppressLint("SetTextI18n")
override fun onDataChange(dataSnapshot:
DataSnapshot) {
var lastDataSnapshot: DataSnapshot? = null

for (childSnapshot in
dataSnapshot.children) {
lastDataSnapshot = childSnapshot
}

if (lastDataSnapshot != null) {
startTimeMillis =
System.currentTimeMillis()
val startTime =
getCurrentTimeFormatted()

// Mendapatkan nilai data dari


dataSnapshot
val suhu =
lastDataSnapshot.child("suhu").getValue(Float::class.java)
?: 0.0f
val kelembapan =
lastDataSnapshot.child("kelembapan").getValue(Float::class.
java) ?: 0.0f
val nitrogen =
lastDataSnapshot.child("nitrogen").getValue(Int::class.java
) ?: 0
val fosfor =
lastDataSnapshot.child("fosfor").getValue(Int::class.java)
?: 0
val kalium =
lastDataSnapshot.child("kalium").getValue(Int::class.java)
?: 0
val ph =
lastDataSnapshot.child("ph").getValue(Float::class.java) ?:
0.0f
tvSuhuData.text = "$suhu°C"
tvHumData.text = "$kelembapan%"
tvNitrogenData.text = "$nitrogen"
tvFosforData.text = "$fosfor"
tvKaliumData.text = "$kalium"
val roundph = Math.round(ph*10.0)/10.0
val absolutph = Math.abs(roundph)
tvPHData.text = "$absolutph"

val stringRequest = object :


StringRequest(
Method.POST, url,
Response.Listener { response ->
endTimeMillis =
System.currentTimeMillis()
val endTime =
getCurrentTimeFormatted()

val responseTimeMillis =
endTimeMillis - startTimeMillis
val responseTimeSeconds =
responseTimeMillis / 1000.0
Toast.makeText(activity,
"Response Time: $responseTimeSeconds seconds",
Toast.LENGTH_SHORT).show()

Log.d("TimeIqqnfo", "startTime:
$startTime")
Log.d("TimeInfo", "endTime:
$endTime")

requireActivity().runOnUiThread
{
try {
val jsonObject =
JSONObject(response)
val data =
jsonObject.getString("Plant")
if (data == "1") {
tvResult.text =
"Padi"
} else if (data == "2")
{
tvResult.text =
"Jagung"
} else if (data == "3")
{
tvResult.text =
"Buncis"
} else if (data == "4")
{
tvResult.text =
"Kacang Merah"
} else if (data == "5")
{
tvResult.text =
"Kacang Gude"
} else if (data == "6")
{
tvResult.text =
"Kacang Hijau"
} else if (data == "7")
{
tvResult.text =
"Gram Hitam"
} else if (data == "8")
{
tvResult.text =
"Delima"
} else if (data == "9")
{
tvResult.text =
"Pisang"
} else if (data ==
"10") {
tvResult.text =
"Mangga"
} else if (data ==
"11") {
tvResult.text =
"Anggur"
} else if (data ==
"12") {
tvResult.text =
"Semangka"
} else if (data ==
"13") {
tvResult.text =
"Melon"
} else if (data ==
"14") {
tvResult.text =
"Apel"
} else if (data ==
"15") {
tvResult.text =
"Jeruk"
} else if (data ==
"16") {
tvResult.text =
"Pepaya"
} else if (data ==
"17") {
tvResult.text =
"Kelapa"
} else if (data ==
"18") {
tvResult.text =
"Kapas"
} else if (data ==
"19") {
tvResult.text =
"Rami/Yute"
}else {
tvResult.text =
"Kopi"
}
} catch (e: JSONException)
{
e.printStackTrace()
}
}
},
Response.ErrorListener { error ->
Toast.makeText(activity,
error.message, Toast.LENGTH_SHORT).show()
}) {

override fun getParams():


Map<String, String> {
val params: MutableMap<String,
String> = HashMap()
params["suhu"] =
suhu.toString()
params["kelembapan"] =
kelembapan.toString()
params["nitrogen"] =
nitrogen.toString()
params["fosfor"] =
fosfor.toString()
params["kalium"] =
kalium.toString()
params["ph"] =
roundph.toString()
return params
}
}
val queue: RequestQueue =
Volley.newRequestQueue(activity)
queue.add(stringRequest)
}
}

override fun onCancelled(error: DatabaseError)


{

}
})
}

private fun getCurrentTimeFormatted(): String {


val currentTimeMillis = System.currentTimeMillis()
val hours = currentTimeMillis / 3600000
val minutes = (currentTimeMillis % 3600000) / 60000
val seconds = ((currentTimeMillis % 3600000) %
60000) / 1000
val milliseconds = ((currentTimeMillis % 3600000) %
60000) % 1000
return "$hours jam, $minutes menit, $seconds detik,
$milliseconds milidetik"
}
}

MACHINE LEARNING
Building Model
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import json

from sklearn import preprocessing


from sklearn.preprocessing import StandardScaler
from sklearn.model_selection import train_test_split
from sklearn.tree import DecisionTreeClassifier
from sklearn import metrics
from sklearn.metrics import confusion_matrix, classification_report
from sklearn.preprocessing import MinMaxScaler
from sklearn.preprocessing import LabelEncoder
from sklearn.metrics import accuracy_score
%matplotlib inline

from google.colab import drive


drive.mount('/content/drive')

data =
pd.read_csv('/content/drive/MyDrive/Kampus/Skripsi/Dataset/Crop_reco
mmendation.csv')
data

data.isnull().sum()

duplicate_rows = data[data.duplicated()]
print("\nNilai Duplikat:")
print(duplicate_rows)

# Fungsi untuk menghilangkan nilai di belakang koma


def remove_decimal(value):
return int(value)
data['humidity'] = data['humidity'].apply(remove_decimal)

data[['temperature', 'ph']] = data[['temperature', 'ph']].round(1)

data

new_data = data[~data['label'].isin(['mothbeans', 'lentil'])]


new_data

new_data = new_data.drop(['rainfall'], axis=1)


new_data = new_data.reset_index(drop=True)
new_data

X = new_data.drop(columns=['label'])
y = new_data['label']

uniq_num = y.nunique()
uniq_val = y.unique()

for i in range(uniq_num):
y.replace(uniq_val[i], i+1, inplace= True)

# membagi data menjadi train dan test untuk setiap atribut dan label
X_train, X_test, y_train, y_test = train_test_split(X, y,
test_size=0.4082482904638631, shuffle=True, random_state=8)

rf = RandomForestClassifier(random_state=10)
lgbm = lgb.LGBMClassifier(verbose=-1, n_estimators=10,
random_state=42)
svm_model = svm.SVC(probability=True)

from sklearn.ensemble import VotingClassifier

# Ensemble of Models
estimator = []
estimator.append(('RF', rf))
estimator.append(('LGBM', lgbm))
estimator.append(('SVM', svm_model))

# Voting Classifier with hard voting


hard_voting = VotingClassifier(estimators = estimator, voting ='hard',
weights=[2, 1, 1], flatten_transform=True)
hard_voting.fit(X_train, y_train)
#Mengevaluasi model pada data validasi
y_pred = hard_voting.predict(X_test)
accuracy = accuracy_score(y_test, y_pred)*100
print("Akurasi pada data testing:", accuracy)

# Menguji performa model pada data pelatihan (opsional)


y_train_pred = hard_voting.predict(X_train)
training_accuracy = accuracy_score(y_train, y_train_pred)*100
print("Akurasi pada data pelatihan:", training_accuracy)

import pickle
with open('ml_model.pkl', 'wb') as file:
pickle.dump(hard_voting, file)

Flask API
app.py
from flask import Flask, request, jsonify
from sklearn.preprocessing import MinMaxScaler
import numpy as np
import pickle

model = pickle.load(open('ml_model.pkl', 'rb'))

app = Flask(__name__)

@app.route('/')
def index():
return "Hello world"

@app.route("/predict", methods=["POST"])

def predict():
nitrogen = request.form.get('nitrogen')
fosfor = request.form.get('fosfor')
kalium = request.form.get('kalium')
suhu = request.form.get('suhu')
kelembapan = request.form.get('kelembapan')
ph = request.form.get('ph')

input_query = np.array([[nitrogen, fosfor, kalium, suhu, kelembapan,


ph]])

recommendation = model.predict(input_query)[0]
return jsonify({"Plant":str(recommendation)})

if __name__ == '__main__':
app.run(debug=True)

vercel.json
{
"version": 2,
"builds": [
{
"src": "app.py",
"use": "@vercel/python"
}
],
"routes": [
{
"src": "/(.*)",
"dest": "app.py"
},
{
"src": "/predict",
"methods": ["POST"],
"dest": "app.py"
}
]
}

requirements.txt
flask
numpy
scikit-learn == 1.2.2
lightgbm

Video Penggunaan Prototype

Untuk melihat video penggunaan prototype dapat dilihat pada link video

berikut : https://youtu.be/8pFQK4VkNho

You might also like