get('station'); $dateTImeFilter = $request->input('date'); $displayDate = $dateTImeFilter ? $dateTImeFilter : now(); $dateFilter = $dateTImeFilter ? Carbon::parse($dateTImeFilter)->format('Y-m-d') :Carbon::today()->format('Y-m-d'); $stations = DB::table('station')->select('stationid', 'name') ->where('rainfall',1) ->orderBy('stationid')->get(); $bindings = []; $stationCondition = ''; if ($stationFilter) { $stationCondition = " AND s.stationid = ?"; $bindings[] = $stationFilter; } $bindings[] = $displayDate; $bindings[] = $dateFilter; $bindings[] = $dateFilter; $bindings[] = $dateFilter; $bindings[] = $dateFilter; $bindings[] = $dateFilter; $bindings[] = $dateFilter; $bindings[] = $dateFilter; $bindings[] = $dateFilter; $bindings[] = $dateFilter; $bindings[] = $dateFilter; $rainfallData = collect(DB::select(" SELECT s.stationid, s.name, s.district, CAST(? AS timestamp) AS selected_timestamp, ( SELECT l2.hourly FROM rainfall l2 WHERE l2.stationid = s.stationid ORDER BY l2.timestamp DESC LIMIT 1 ) AS hourly, ( SELECT l3.daily FROM rainfall l3 WHERE l3.stationid = s.stationid ORDER BY l3.timestamp DESC LIMIT 1 ) AS daily, ( SELECT l4.timestamp FROM rainfall l4 WHERE l4.stationid = s.stationid AND DATE(l4.timestamp) <= CAST(? AS date) ORDER BY l4.timestamp DESC LIMIT 1 ) AS last_updated, MAX(CASE WHEN DATE(l.timestamp) = CAST(? as date) - INTERVAL '6 days' THEN l.daily END) AS day1, MAX(CASE WHEN DATE(l.timestamp) = CAST(? as date) - INTERVAL '5 days' THEN l.daily END) AS day2, MAX(CASE WHEN DATE(l.timestamp) = CAST(? as date) - INTERVAL '4 days' THEN l.daily END) AS day3, MAX(CASE WHEN DATE(l.timestamp) = CAST(? as date) - INTERVAL '3 days' THEN l.daily END) AS day4, MAX(CASE WHEN DATE(l.timestamp) = CAST(? as date) - INTERVAL '2 days' THEN l.daily END) AS day5, MAX(CASE WHEN DATE(l.timestamp) = CAST(? as date) - INTERVAL '1 day' THEN l.daily END) AS day6, MAX(CASE WHEN DATE(l.timestamp) = CAST(? as date) THEN l.daily END) AS day7 FROM station s INNER JOIN rainfall l ON s.stationid = l.stationid WHERE TO_CHAR(l.timestamp, 'HH24:MI:SS') != '00:00:00' AND l.timestamp >= CAST(? as date) - INTERVAL '6 days' $stationCondition GROUP BY s.stationid, s.name, s.district ", $bindings )); $lastupdate = DB::table('rainfall')->max('timestamp'); $dates = collect(range(6,1))->map(fn($i)=>Carbon::parse($dateFilter)->subDays($i)->format('d/m/Y')); return view('layout.rainfall',compact('rainfallData','lastupdate','dates','stations','displayDate')); } // Function For 6 Hours Rainfall Data for Each Station For Early Warning Threshold public function rainfallSum(Request $request) { $stationFilter = $request->input('station'); $dateFilter = $request->input('date'); // If no date submitted → use current local time $displayDate = $dateFilter ? $dateFilter : now('Asia/Kuala_Lumpur'); // Convert to Y-m-d H:i:s for SQL comparison $sqlDate = \Carbon\Carbon::parse($displayDate)->format('Y-m-d H:i:s'); // Fetch stations $stations = DB::table('station')->select('stationid', 'name')->where('rainfall',1)->orderBy('stationid')->get(); // Build SQL query $sql = " WITH latest AS ( SELECT s.stationid, s.name, s.district, MAX(l.timestamp) AS latest_timestamp FROM station s INNER JOIN rainfall l ON s.stationid = l.stationid WHERE 1=1 "; $bindings = []; // Apply date filter if ($dateFilter) { $sql .= " AND l.timestamp = :dateFilter "; $bindings['dateFilter'] = $sqlDate; } $sql .= " GROUP BY s.stationid, s.name, s.district ), hourly_intervals AS ( SELECT s.stationid, s.name, s.district, l.currentrf, l.timestamp, EXTRACT(EPOCH FROM (lt.latest_timestamp - l.timestamp)) / 3600 AS hours_diff, lt.latest_timestamp FROM station s INNER JOIN rainfall l ON s.stationid = l.stationid INNER JOIN latest lt ON lt.stationid = s.stationid WHERE l.timestamp <= lt.latest_timestamp AND l.timestamp > lt.latest_timestamp - INTERVAL '6 hours' ) SELECT stationid, name, district, MAX(CASE WHEN hours_diff < 1 THEN currentrf END) AS hour1_value, MAX(CASE WHEN hours_diff < 1 THEN TO_CHAR(timestamp, 'HH24:MI:SS') END) AS hour1_time, MAX(CASE WHEN hours_diff >= 1 AND hours_diff < 2 THEN currentrf END) AS hour2_value, MAX(CASE WHEN hours_diff >= 1 AND hours_diff < 2 THEN TO_CHAR(timestamp, 'HH24:MI:SS') END) AS hour2_time, MAX(CASE WHEN hours_diff >= 2 AND hours_diff < 3 THEN currentrf END) AS hour3_value, MAX(CASE WHEN hours_diff >= 2 AND hours_diff < 3 THEN TO_CHAR(timestamp, 'HH24:MI:SS') END) AS hour3_time, MAX(CASE WHEN hours_diff >= 3 AND hours_diff < 4 THEN currentrf END) AS hour4_value, MAX(CASE WHEN hours_diff >= 3 AND hours_diff < 4 THEN TO_CHAR(timestamp, 'HH24:MI:SS') END) AS hour4_time, MAX(CASE WHEN hours_diff >= 4 AND hours_diff < 5 THEN currentrf END) AS hour5_value, MAX(CASE WHEN hours_diff >= 4 AND hours_diff < 5 THEN TO_CHAR(timestamp, 'HH24:MI:SS') END) AS hour5_time, MAX(CASE WHEN hours_diff >= 5 AND hours_diff < 6 THEN currentrf END) AS hour6_value, MAX(CASE WHEN hours_diff >= 5 AND hours_diff < 6 THEN TO_CHAR(timestamp, 'HH24:MI:SS') END) AS hour6_time, MAX(latest_timestamp) AS last_update FROM hourly_intervals WHERE 1=1 "; // Apply station filter if ($stationFilter) { $sql .= " AND stationid = :stationFilter "; $bindings['stationFilter'] = $stationFilter; } $sql .= " GROUP BY stationid, name, district ORDER BY stationid;"; // Execute query $thresholdData = collect(DB::select($sql, $bindings)); $lastupdate = DB::table('rainfall')->max('timestamp'); return view('layout.threshold', compact('thresholdData', 'stations', 'displayDate','lastupdate')); } // Function retrieve Hourly rainfall Graph For Each Station public function rainfallGraph($stationid) { $graphData = DB::table('rainfall') ->select(DB::raw("TO_CHAR(timestamp, 'HH24:MI') AS hour"), DB::raw("CASE WHEN TO_CHAR(timestamp, 'HH24:MI') LIKE '00:%' THEN 0 ELSE hourly END AS hourly") ) ->whereDate('timestamp', today()) ->whereRaw("EXTRACT(MINUTE FROM timestamp) = 0") ->where('stationid', $stationid) ->orderBy('timestamp') ->get(); return response()->json($graphData); // $graphData = DB::table('rainfall') // ->select( // DB::raw("DATE(timestamp) as date"), // DB::raw("TO_CHAR(timestamp, 'HH24:MI') AS time_slot"), // 'currentrf' // ) // ->where('stationid', $stationid) // ->whereBetween('timestamp', [ // now()->subDays(7)->startOfDay(), // now()->endOfDay() // ]) // ->whereRaw("EXTRACT(MINUTE FROM timestamp) % 5 = 0") // only multiples of 5 minutes // ->orderBy('timestamp') // ->get(); } // Function retrieve data of 6 Hours Rainfall fo Graph Page public function graphData($stationid,$dates) { $dates = urldecode($dates); $latest = DB::table('rainfall') ->where('stationid', $stationid) ->where('timestamp',$dates) ->max('timestamp'); if (!$latest) { // no data in table return response()->json([ 'labels' => [], 'data' => [] ]); } // 2. Generate 6 hourly timestamps counting back from latest $labels = []; $times = []; $latestCarbon = Carbon::parse($latest); for ($i = 5; $i >= 0; $i--) { $ts = $latestCarbon->copy()->subHours($i); $labels[] = $ts->format('H:i'); // chart label $times[] = $ts; // for query matching } // 3. Query rainfall data for these 6 timestamps $graphData = DB::table('rainfall') ->select( DB::raw("TO_CHAR(timestamp, 'HH24:MI') as time"), 'hourly' ) ->where('stationid', $stationid) ->whereBetween('timestamp', [ $latestCarbon->copy()->subHours(5), $latestCarbon ]) ->orderBy('timestamp') ->get(); // 4. Map data to labels, fill missing hours with 0 $data = []; foreach ($labels as $label) { $record = $graphData->firstWhere('time', $label); $data[] = $record ? $record->hourly : 0; } return response()->json([ 'labels' => $labels, 'data' => $data ]); } //Return View Graph Page public function graphPage($stationid,$dates) { // $station = DB::table('station')->where('stationid',$stationid)->first(); return view('layout.graph.rainfall',compact('stationid','dates')); } // Function for Retrieve Historical Rainfall Data public function historicalRainfall(Request $request) { $stationFilter = $request->get('station'); $startDateInput = $request->input('startdate'); $endDateInput = $request->input('enddate'); $displayDate = $startDateInput ?: now(); $displayEndDate = $endDateInput ?: now(); $stations = DB::table('station') ->select('stationid', 'name') ->where('rainfall', 1) ->orderBy('stationid') ->get(); $startDate = Carbon::parse($startDateInput)->toDateString(); $endDate = Carbon::parse($endDateInput)->toDateString(); // Build the hourly columns without referencing grouped outer query $hourlyColumns = []; for ($i = 0; $i <= 23; $i++) { $hour = sprintf("%02d", $i); $hourlyColumns[] = " MAX(CASE WHEN EXTRACT(HOUR FROM timestamp) = $i THEN hourly END) AS hour_$hour "; } $hourlyColumnSql = implode(",", $hourlyColumns); // Use a CTE to get latest per hour per day first $sql = " WITH latest_per_hour AS ( SELECT DISTINCT ON (stationid, timestamp::date, EXTRACT(HOUR FROM timestamp)) stationid, timestamp, hourly, daily FROM rainfall WHERE stationid = :stationid AND timestamp::date BETWEEN :startDate AND :endDate ORDER BY stationid, timestamp::date, EXTRACT(HOUR FROM timestamp), timestamp DESC ) SELECT timestamp::date AS date, stationid, $hourlyColumnSql, MAX(daily) FILTER (WHERE EXTRACT(HOUR FROM timestamp) <> 0) AS total_24 FROM latest_per_hour GROUP BY timestamp::date, stationid ORDER BY timestamp::date "; $historyData = collect(DB::select($sql, [ 'stationid' => $stationFilter, 'startDate' => $startDate, 'endDate' => $endDate ])); return view('layout.historicalrainfall', compact( 'historyData', 'stations', 'displayDate', 'displayEndDate' )); } // Function for export Historical Rainfall To Excel File public function exportHourlyRainfallExcel(Request $request) { $stationid = $request->get('station'); $startDate = $request->input('startdate'); $endDate = $request->input('enddate'); $startDate2 = Carbon::parse($startDate)->toDateString(); $endDate2 = Carbon::parse($endDate)->toDateString(); return Excel::download( new HourlyRainfallExport($stationid,$startDate,$endDate),"Hourly Rainfall {$stationid} {$startDate2} - {$endDate2}.xlsx" ); } }