Upload 7 files
Browse files- app.py +187 -0
- requirement.txt +9 -0
- static/alarn_tune.mp3 +0 -0
- static/images/img.png +0 -0
- svm_poly_model.pkl +3 -0
- templates/index.html +167 -0
- templates/predict.html +186 -0
app.py
ADDED
@@ -0,0 +1,187 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from flask import Flask, render_template, request, redirect, url_for, session,jsonify
|
2 |
+
import joblib
|
3 |
+
import pandas as pd
|
4 |
+
import numpy as np
|
5 |
+
import requests
|
6 |
+
import json
|
7 |
+
import plotly.graph_objects as go
|
8 |
+
|
9 |
+
app = Flask(__name__)
|
10 |
+
|
11 |
+
# Load the SVM model
|
12 |
+
svm_poly_model = joblib.load('svm_poly_model.pkl')
|
13 |
+
|
14 |
+
# Label encoding mappings for SVM model
|
15 |
+
crop_type_mapping = {
|
16 |
+
'BANANA': 0, 'BEAN': 1, 'CABBAGE': 2, 'CITRUS': 3, 'COTTON': 4,
|
17 |
+
'MAIZE': 5, 'MELON': 6, 'MUSTARD': 7, 'ONION': 8, 'OTHER': 9,
|
18 |
+
'POTATO': 10, 'RICE': 11, 'SOYABEAN': 12, 'SUGARCANE': 13,
|
19 |
+
'TOMATO': 14, 'WHEAT': 15
|
20 |
+
}
|
21 |
+
|
22 |
+
soil_type_mapping = {'DRY': 0, 'HUMID': 1, 'WET': 2}
|
23 |
+
weather_condition_mapping = {'NORMAL': 0, 'RAINY': 1, 'SUNNY': 2, 'WINDY': 3}
|
24 |
+
|
25 |
+
|
26 |
+
# Fetch weather data from the OpenWeatherMap API
|
27 |
+
def get_weather(city):
|
28 |
+
api_key = "b3c62ae7f7ad5fc3cb0a7b56cb7cbda6"
|
29 |
+
url = f"https://api.openweathermap.org/data/2.5/weather?q={city}&appid={api_key}"
|
30 |
+
try:
|
31 |
+
response = requests.get(url)
|
32 |
+
response.raise_for_status() # Raise an exception for any HTTP errors
|
33 |
+
except requests.exceptions.HTTPError as err:
|
34 |
+
return None, None, None, None
|
35 |
+
|
36 |
+
try:
|
37 |
+
data = json.loads(response.text)
|
38 |
+
if data['cod'] != 200:
|
39 |
+
return None, None, None, None
|
40 |
+
except json.JSONDecodeError as err:
|
41 |
+
return None, None, None, None
|
42 |
+
|
43 |
+
# Extract relevant weather information
|
44 |
+
weather_description = data['weather'][0]['description']
|
45 |
+
temperature = data['main']['temp']
|
46 |
+
humidity = data['main']['humidity']
|
47 |
+
pressure = data['main']['pressure']
|
48 |
+
# Convert temperature from Kelvin to Celsius
|
49 |
+
temperature = round(temperature - 273.15, 2)
|
50 |
+
|
51 |
+
return temperature, humidity, weather_description, pressure
|
52 |
+
|
53 |
+
|
54 |
+
@app.route('/')
|
55 |
+
def index():
|
56 |
+
return render_template('index.html')
|
57 |
+
|
58 |
+
|
59 |
+
@app.route('/fetch_weather', methods=['GET'])
|
60 |
+
def fetch_weather():
|
61 |
+
city = request.args.get('city')
|
62 |
+
if city:
|
63 |
+
temperature, humidity, weather_description, pressure = get_weather(city)
|
64 |
+
if temperature is not None:
|
65 |
+
return json.dumps({
|
66 |
+
'description': weather_description.capitalize(),
|
67 |
+
'temperature': temperature,
|
68 |
+
'humidity': humidity,
|
69 |
+
'pressure': pressure
|
70 |
+
})
|
71 |
+
return json.dumps(None) # Return None if weather couldn't be fetched
|
72 |
+
|
73 |
+
|
74 |
+
|
75 |
+
@app.route('/predict', methods=['POST'])
|
76 |
+
def predict():
|
77 |
+
if request.method == 'POST':
|
78 |
+
crop_type = request.form['crop_type']
|
79 |
+
soil_type = request.form['soil_type']
|
80 |
+
city = request.form['city']
|
81 |
+
motor_capacity = float(request.form['motor_capacity'])
|
82 |
+
|
83 |
+
# Get weather data
|
84 |
+
temperature, humidity, weather_description, pressure = get_weather(city)
|
85 |
+
|
86 |
+
# Auto-fill weather condition based on description
|
87 |
+
if temperature is None:
|
88 |
+
auto_weather_condition = 'NORMAL'
|
89 |
+
temperature = 32.0
|
90 |
+
else:
|
91 |
+
auto_weather_condition = ('SUNNY' if 'clear' in weather_description.lower() else
|
92 |
+
'RAINY' if 'rain' in weather_description.lower() else
|
93 |
+
'WINDY' if 'wind' in weather_description.lower() else
|
94 |
+
'NORMAL')
|
95 |
+
|
96 |
+
# Encode inputs for the model
|
97 |
+
crop_type_encoded = crop_type_mapping[crop_type]
|
98 |
+
soil_type_encoded = soil_type_mapping[soil_type]
|
99 |
+
weather_condition_encoded = weather_condition_mapping[auto_weather_condition]
|
100 |
+
|
101 |
+
# Create DataFrame for input
|
102 |
+
user_data = pd.DataFrame({
|
103 |
+
'CROP TYPE': [crop_type_encoded],
|
104 |
+
'SOIL TYPE': [soil_type_encoded],
|
105 |
+
'TEMPERATURE': [temperature],
|
106 |
+
'WEATHER CONDITION': [weather_condition_encoded]
|
107 |
+
})
|
108 |
+
|
109 |
+
# Predict water requirement
|
110 |
+
water_requirement = svm_poly_model.predict(user_data)[0]
|
111 |
+
|
112 |
+
# Calculate estimated time duration
|
113 |
+
estimated_time_duration = water_requirement / motor_capacity if motor_capacity > 0 else 0
|
114 |
+
time_unit = "seconds" if estimated_time_duration < 1 else "minutes"
|
115 |
+
estimated_time_duration = estimated_time_duration * 60 if time_unit == "seconds" else estimated_time_duration
|
116 |
+
|
117 |
+
# Create the gauge charts for water requirement and estimated time
|
118 |
+
water_gauge = go.Figure(go.Indicator(
|
119 |
+
mode="gauge+number",
|
120 |
+
value=water_requirement,
|
121 |
+
title={"text": "Water Requirement (m³/sq.m)"},
|
122 |
+
gauge={
|
123 |
+
"axis": {"range": [None, 100]},
|
124 |
+
"bar": {"color": "blue"},
|
125 |
+
"steps": [
|
126 |
+
{"range": [0, 20], "color": "lightgray"},
|
127 |
+
{"range": [20, 50], "color": "yellow"},
|
128 |
+
{"range": [50, 100], "color": "green"}
|
129 |
+
]
|
130 |
+
}
|
131 |
+
))
|
132 |
+
|
133 |
+
# Determine gauge axis range based on the time unit
|
134 |
+
max_range = 60 if time_unit == "seconds" else 120
|
135 |
+
|
136 |
+
time_gauge = go.Figure(go.Indicator(
|
137 |
+
mode="gauge+number",
|
138 |
+
value=round(estimated_time_duration, 2),
|
139 |
+
title={"text": f"Estimated Time ({time_unit.capitalize()})"},
|
140 |
+
gauge={
|
141 |
+
"axis": {"range": [None, max_range]},
|
142 |
+
"bar": {"color": "blue"},
|
143 |
+
"steps": [
|
144 |
+
{"range": [0, max_range * 0.33], "color": "lightgray"},
|
145 |
+
{"range": [max_range * 0.33, max_range * 0.66], "color": "yellow"},
|
146 |
+
{"range": [max_range * 0.66, max_range], "color": "green"}
|
147 |
+
]
|
148 |
+
}
|
149 |
+
))
|
150 |
+
|
151 |
+
# Send gauge charts to the prediction page
|
152 |
+
water_gauge_path = water_gauge.to_html(full_html=False)
|
153 |
+
time_gauge_path = time_gauge.to_html(full_html=False)
|
154 |
+
|
155 |
+
return render_template('predict.html',
|
156 |
+
water_requirement=round(water_requirement, 2),
|
157 |
+
estimated_time_duration=round(estimated_time_duration, 2),
|
158 |
+
time_unit=time_unit,
|
159 |
+
weather_info=f"Weather in {city}: {weather_description.capitalize()}<br>"
|
160 |
+
f"Temperature: {temperature}°C<br>"
|
161 |
+
f"Humidity: {humidity}%<br>"
|
162 |
+
f"Pressure: {pressure} hPa<br>",
|
163 |
+
water_gauge=water_gauge_path,
|
164 |
+
time_gauge=time_gauge_path)
|
165 |
+
|
166 |
+
return redirect(url_for('index'))
|
167 |
+
|
168 |
+
|
169 |
+
@app.route('/start_motor', methods=['POST'])
|
170 |
+
def start_motor():
|
171 |
+
estimated_time_duration = float(request.json.get('estimated_time_duration'))
|
172 |
+
time_unit = request.json.get('time_unit', 'seconds') # Default unit is seconds
|
173 |
+
# Convert time to seconds if it's in minutes
|
174 |
+
if estimated_time_duration < 10:
|
175 |
+
estimated_time_duration_seconds = estimated_time_duration * 60
|
176 |
+
else:
|
177 |
+
estimated_time_duration_seconds = estimated_time_duration
|
178 |
+
|
179 |
+
# Assuming this function will trigger the motor start, we will just send the confirmation
|
180 |
+
print(f"Starting motor for {estimated_time_duration_seconds} seconds")
|
181 |
+
|
182 |
+
# Return a response indicating that the motor has started
|
183 |
+
return jsonify({"status": "motor_started", "estimated_time_duration": estimated_time_duration_seconds})
|
184 |
+
|
185 |
+
|
186 |
+
if __name__ == "__main__":
|
187 |
+
app.run(debug=True)
|
requirement.txt
ADDED
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
gunicorn
|
2 |
+
pandas
|
3 |
+
numpy
|
4 |
+
matplotlib
|
5 |
+
joblib==1.4.2
|
6 |
+
plotly
|
7 |
+
scikit-learn==1.5.2
|
8 |
+
flask
|
9 |
+
requests
|
static/alarn_tune.mp3
ADDED
Binary file (229 kB). View file
|
|
static/images/img.png
ADDED
![]() |
svm_poly_model.pkl
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:b60a7814f3e851178e888f92530d7a5dbdeb4a66557f43e0fe7e43d09335a276
|
3 |
+
size 124910
|
templates/index.html
ADDED
@@ -0,0 +1,167 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<!DOCTYPE html>
|
2 |
+
<html lang="en">
|
3 |
+
<head>
|
4 |
+
<meta charset="UTF-8">
|
5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6 |
+
<title>Irrigation Water Requirement Prediction</title>
|
7 |
+
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
|
8 |
+
<style>
|
9 |
+
body {
|
10 |
+
background-color: #f0fff0; /* Very light green */
|
11 |
+
}
|
12 |
+
.container {
|
13 |
+
border: 1px solid #28a745; /* Green border */
|
14 |
+
padding: 20px;
|
15 |
+
margin: 40px auto;
|
16 |
+
background-color: white;
|
17 |
+
border-radius: 10px;
|
18 |
+
}
|
19 |
+
/* Add these styles */
|
20 |
+
#weather_info {
|
21 |
+
background-color: #f8f9fa; /* Light grey background */
|
22 |
+
border: 2px solid #000000; /* Dark black border */
|
23 |
+
padding: 15px; /* Padding for spacing inside the box */
|
24 |
+
border-radius: 5px; /* Optional: Rounded corners */
|
25 |
+
}
|
26 |
+
h1 {
|
27 |
+
color: #28a745; /* Bold green heading */
|
28 |
+
text-align: center;
|
29 |
+
font-weight: bold;
|
30 |
+
}
|
31 |
+
.input-container {
|
32 |
+
display: flex;
|
33 |
+
justify-content: space-between;
|
34 |
+
height: 100%; /* Ensure both sides are the same height */
|
35 |
+
}
|
36 |
+
.left-input {
|
37 |
+
width: 53%;
|
38 |
+
border-right: 2px solid #28a745;
|
39 |
+
padding-right: 20px;
|
40 |
+
}
|
41 |
+
.right-image {
|
42 |
+
width: 45%;
|
43 |
+
display: flex;
|
44 |
+
justify-content: center;
|
45 |
+
align-items: center;
|
46 |
+
height: 200%; /* Ensure full height */
|
47 |
+
margin-top: 50px;
|
48 |
+
}
|
49 |
+
.right-image img {
|
50 |
+
width: 100%;
|
51 |
+
height: 100%; /* Match the height of the left container */
|
52 |
+
object-fit: contain; /* Ensure the image scales well */
|
53 |
+
}
|
54 |
+
.form-control {
|
55 |
+
border-color: #28a745; /* Green border */
|
56 |
+
background-color: #f0fff0; /* Light green shading */
|
57 |
+
}
|
58 |
+
.btn-green {
|
59 |
+
background-color: #28a745;
|
60 |
+
color: white;
|
61 |
+
font-weight: bold;
|
62 |
+
width: 100%;
|
63 |
+
margin-top: 10px;
|
64 |
+
}
|
65 |
+
</style>
|
66 |
+
</head>
|
67 |
+
<body>
|
68 |
+
|
69 |
+
<div class="container">
|
70 |
+
<h1>Irrigation Water Requirement Prediction</h1>
|
71 |
+
<form action="/predict" method="POST">
|
72 |
+
<div class="input-container">
|
73 |
+
<div class="left-input">
|
74 |
+
<!-- Crop Type Input -->
|
75 |
+
<div class="form-group">
|
76 |
+
<label for="crop_type">Crop Type</label>
|
77 |
+
<select class="form-control" id="crop_type" name="crop_type" required>
|
78 |
+
<option value="BANANA">Banana</option>
|
79 |
+
<option value="BEAN">BEAN</option>
|
80 |
+
<option value="CABBAGE">CABBAGE</option>
|
81 |
+
<option value="CITRUS">CITRUS</option>
|
82 |
+
<option value="COTTON">COTTON</option>
|
83 |
+
<option value="MAIZE">MAIZE</option>
|
84 |
+
<option value="MELON">MELON</option>
|
85 |
+
<option value="MUSTARD">MUSTARD</option>
|
86 |
+
<option value="ONION">ONION</option>
|
87 |
+
<option value="OTHER">OTHER</option>
|
88 |
+
<option value="POTATO">POTATO</option>
|
89 |
+
<option value="RICE">RICE</option>
|
90 |
+
<option value="SOYABEAN">SOYABEAN</option>
|
91 |
+
<option value="SUGARCANE">SUGARCANE</option>
|
92 |
+
<option value="TOMATO">TOMATO</option>
|
93 |
+
<option value="WHEAT">WHEAT</option>
|
94 |
+
<!-- Add other options as needed -->
|
95 |
+
</select>
|
96 |
+
</div>
|
97 |
+
|
98 |
+
<!-- Soil Type Input -->
|
99 |
+
<div class="form-group">
|
100 |
+
<label for="soil_type">Soil Type</label>
|
101 |
+
<select class="form-control" id="soil_type" name="soil_type" required>
|
102 |
+
<option value="DRY">Dry</option>
|
103 |
+
<option value="HUMID">Humid</option>
|
104 |
+
<option value="WET">Wet</option>
|
105 |
+
</select>
|
106 |
+
</div>
|
107 |
+
|
108 |
+
<!-- City Input and Fetch Weather Button -->
|
109 |
+
<div class="form-group">
|
110 |
+
<label for="city">City</label>
|
111 |
+
<input type="text" class="form-control" id="city" name="city" placeholder="Enter city for weather" required>
|
112 |
+
</div>
|
113 |
+
<button type="button" class="btn btn-green" onclick="fetchWeather()">Fetch Weather Data</button>
|
114 |
+
<!-- Weather Info will be inserted below when fetched -->
|
115 |
+
<div id="weather_info" class="mt-3" style="display: none;">
|
116 |
+
<p><strong>Weather Info:</strong></p>
|
117 |
+
<div id="weather_data"></div>
|
118 |
+
</div>
|
119 |
+
<!-- Motor Capacity Input -->
|
120 |
+
<div class="form-group mt-3">
|
121 |
+
<label for="motor_capacity">Motor Capacity (liters/sec)</label>
|
122 |
+
<input type="text" class="form-control" id="motor_capacity" name="motor_capacity" required>
|
123 |
+
</div>
|
124 |
+
|
125 |
+
<!-- Predict Button -->
|
126 |
+
<button type="submit" class="btn btn-green">Predict Water Requirement</button>
|
127 |
+
</div>
|
128 |
+
|
129 |
+
<div class="right-image">
|
130 |
+
<img src="/static/images/img.png" alt="Decorative Image">
|
131 |
+
</div>
|
132 |
+
</div>
|
133 |
+
</form>
|
134 |
+
</div>
|
135 |
+
|
136 |
+
<script>
|
137 |
+
function fetchWeather() {
|
138 |
+
const city = document.getElementById('city').value;
|
139 |
+
if (city) {
|
140 |
+
fetch(`/fetch_weather?city=${city}`)
|
141 |
+
.then(response => response.json())
|
142 |
+
.then(data => {
|
143 |
+
if (data) {
|
144 |
+
document.getElementById('weather_data').innerHTML = `
|
145 |
+
Weather: ${data.description}<br>
|
146 |
+
Temperature: ${data.temperature}°C<br>
|
147 |
+
Humidity: ${data.humidity}%<br>
|
148 |
+
Pressure: ${data.pressure} hPa
|
149 |
+
`;
|
150 |
+
document.getElementById('weather_info').style.display = 'block'; // Show the weather info box
|
151 |
+
} else {
|
152 |
+
document.getElementById('weather_data').innerHTML = 'Weather data not available';
|
153 |
+
document.getElementById('weather_info').style.display = 'block';
|
154 |
+
}
|
155 |
+
})
|
156 |
+
.catch(error => {
|
157 |
+
console.error('Error fetching weather:', error);
|
158 |
+
document.getElementById('weather_data').innerHTML = 'Error fetching weather data';
|
159 |
+
document.getElementById('weather_info').style.display = 'block';
|
160 |
+
});
|
161 |
+
}
|
162 |
+
}
|
163 |
+
</script>
|
164 |
+
|
165 |
+
|
166 |
+
</body>
|
167 |
+
</html>
|
templates/predict.html
ADDED
@@ -0,0 +1,186 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<!DOCTYPE html>
|
2 |
+
<html lang="en">
|
3 |
+
<head>
|
4 |
+
<meta charset="UTF-8">
|
5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6 |
+
<title>Prediction Results</title>
|
7 |
+
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
|
8 |
+
<style>
|
9 |
+
.container {
|
10 |
+
margin-top: 20px;
|
11 |
+
padding: 20px;
|
12 |
+
border: 1px solid #ddd;
|
13 |
+
border-radius: 10px;
|
14 |
+
}
|
15 |
+
h1 {
|
16 |
+
color: green;
|
17 |
+
font-weight: bold;
|
18 |
+
}
|
19 |
+
.result-container {
|
20 |
+
padding: 20px;
|
21 |
+
margin-top: 20px;
|
22 |
+
}
|
23 |
+
.result-container .row {
|
24 |
+
justify-content: center;
|
25 |
+
}
|
26 |
+
.form-control {
|
27 |
+
height: 45px;
|
28 |
+
font-size: 18px;
|
29 |
+
text-align: center;
|
30 |
+
font-weight: bold; /* Bold text */
|
31 |
+
color: black; /* Black text */
|
32 |
+
border: 2px solid #28a745; /* Green border */
|
33 |
+
}
|
34 |
+
.result {
|
35 |
+
text-align: center;
|
36 |
+
}
|
37 |
+
.gauge-container {
|
38 |
+
margin-top: 20px;
|
39 |
+
}
|
40 |
+
.gauge-container h5 {
|
41 |
+
margin-bottom: 10px;
|
42 |
+
}
|
43 |
+
.btn-green {
|
44 |
+
background-color: green;
|
45 |
+
color: white;
|
46 |
+
}
|
47 |
+
|
48 |
+
/* New styles below */
|
49 |
+
.info-text {
|
50 |
+
font-size: 24px; /* Increased font size */
|
51 |
+
font-weight: bold;
|
52 |
+
color: black;
|
53 |
+
margin-top: 40px;
|
54 |
+
text-align: center; /* Center-aligned */
|
55 |
+
}
|
56 |
+
.camera-container {
|
57 |
+
margin-top: 20px;
|
58 |
+
text-align: center;
|
59 |
+
display: none; /* Hidden by default, shown after button click */
|
60 |
+
}
|
61 |
+
.timer {
|
62 |
+
font-size: 36px; /* Increased size */
|
63 |
+
color: white; /* White text */
|
64 |
+
background-color: green; /* Green background */
|
65 |
+
font-weight: bold; /* Bold font */
|
66 |
+
padding: 20px;
|
67 |
+
border-radius: 5px;
|
68 |
+
display: inline-block;
|
69 |
+
}
|
70 |
+
video {
|
71 |
+
width: 100%;
|
72 |
+
height: auto;
|
73 |
+
border: 1px solid #ddd;
|
74 |
+
}
|
75 |
+
.btn-start {
|
76 |
+
margin-top: 20px;
|
77 |
+
background-color: green;
|
78 |
+
color: white;
|
79 |
+
font-size: 18px;
|
80 |
+
padding: 10px 20px;
|
81 |
+
}
|
82 |
+
.alert-message {
|
83 |
+
font-size: 36px; /* Increased size for alert message */
|
84 |
+
color: red;
|
85 |
+
font-weight: bold;
|
86 |
+
margin-top: 20px;
|
87 |
+
text-align: center;
|
88 |
+
}
|
89 |
+
</style>
|
90 |
+
</head>
|
91 |
+
<body>
|
92 |
+
<div class="container">
|
93 |
+
<h1 class="text-center">Water Requirement Prediction Results</h1>
|
94 |
+
<div class="result-container row">
|
95 |
+
<div class="col-md-6">
|
96 |
+
<div class="form-group">
|
97 |
+
<label for="water_requirement">Water Requirement Prediction (m³/sq.m):</label>
|
98 |
+
<input type="text" class="form-control" id="water_requirement" value="{{ water_requirement }}" readonly>
|
99 |
+
</div>
|
100 |
+
<div class="gauge-container">
|
101 |
+
<h5>Water Requirement Gauge:</h5>
|
102 |
+
{{ water_gauge|safe }}
|
103 |
+
</div>
|
104 |
+
</div>
|
105 |
+
|
106 |
+
<div class="col-md-6">
|
107 |
+
<div class="form-group">
|
108 |
+
<label for="estimated_time">Estimated Time Duration (seconds) for which motor should be On:</label>
|
109 |
+
<input type="text" class="form-control" id="estimated_time" value="{{ estimated_time_duration }} {{ time_unit }}" readonly>
|
110 |
+
</div>
|
111 |
+
<div class="gauge-container">
|
112 |
+
<h5>Estimated Motor On-Time Gauge:</h5>
|
113 |
+
{{ time_gauge|safe }}
|
114 |
+
</div>
|
115 |
+
</div>
|
116 |
+
</div>
|
117 |
+
|
118 |
+
<!-- New section below -->
|
119 |
+
<div class="info-text">
|
120 |
+
Want to automatically inspect your irrigation process using AI-driven Irrigation Monitoring?
|
121 |
+
<br><strong>Press "Start Motor" button</strong>
|
122 |
+
<br>Then click the green <strong>Start</strong> button below.
|
123 |
+
</div>
|
124 |
+
|
125 |
+
<!-- "Start Motor" Button -->
|
126 |
+
<div class="text-center">
|
127 |
+
<button id="startMotor" class="btn btn-start">Start Motor</button>
|
128 |
+
</div>
|
129 |
+
|
130 |
+
<div class="camera-container">
|
131 |
+
<video id="videoElement" autoplay></video>
|
132 |
+
<div class="timer" id="timer"></div>
|
133 |
+
</div>
|
134 |
+
|
135 |
+
<div class="alert-message" id="alertMessage"></div>
|
136 |
+
</div>
|
137 |
+
|
138 |
+
<script>
|
139 |
+
// Access camera and start video stream
|
140 |
+
navigator.mediaDevices.getUserMedia({ video: { facingMode: 'environment' } })
|
141 |
+
.then(function(stream) {
|
142 |
+
document.getElementById('videoElement').srcObject = stream;
|
143 |
+
})
|
144 |
+
.catch(function(err) {
|
145 |
+
console.log("Error: " + err);
|
146 |
+
});
|
147 |
+
|
148 |
+
document.getElementById('startMotor').addEventListener('click', function() {
|
149 |
+
let estimatedTime = {{ estimated_time_duration }};
|
150 |
+
if (estimatedTime < 10) {
|
151 |
+
estimatedTime = estimatedTime * 60; // Convert minutes to seconds
|
152 |
+
}
|
153 |
+
let timeUnit = "{{ time_unit }}";
|
154 |
+
|
155 |
+
// Show the camera container after the button is clicked
|
156 |
+
document.querySelector('.camera-container').style.display = 'block';
|
157 |
+
|
158 |
+
// Start the timer
|
159 |
+
let timer = document.getElementById('timer');
|
160 |
+
let timeRemaining = parseInt(estimatedTime, 10); // Convert to integer
|
161 |
+
let countdown = setInterval(function() {
|
162 |
+
let seconds = timeRemaining;
|
163 |
+
timer.textContent = seconds + "s";
|
164 |
+
if (timeRemaining <= 0) {
|
165 |
+
clearInterval(countdown);
|
166 |
+
// Play beep sound
|
167 |
+
let beep = new Audio('/static/alarn_tune.mp3');
|
168 |
+
beep.play();
|
169 |
+
|
170 |
+
// Display alert message
|
171 |
+
document.getElementById('alertMessage').textContent = "Stop Irrigation!";
|
172 |
+
}
|
173 |
+
timeRemaining--;
|
174 |
+
}, 1000);
|
175 |
+
|
176 |
+
fetch('/start_motor', {
|
177 |
+
method: 'POST',
|
178 |
+
headers: {
|
179 |
+
'Content-Type': 'application/json',
|
180 |
+
},
|
181 |
+
body: JSON.stringify({ estimated_time_duration: estimated_time_duration_seconds })
|
182 |
+
});
|
183 |
+
});
|
184 |
+
</script>
|
185 |
+
</body>
|
186 |
+
</html>
|