append to csv
This commit is contained in:
parent
154792d23d
commit
4452183305
@ -1,3 +1,6 @@
|
|||||||
|
import axios from "axios";
|
||||||
|
import React, { useState, useEffect } from "react";
|
||||||
|
|
||||||
export type SiteName = 'Site A' | 'Site B' | 'Site C';
|
export type SiteName = 'Site A' | 'Site B' | 'Site C';
|
||||||
|
|
||||||
interface SiteStatusProps {
|
interface SiteStatusProps {
|
||||||
@ -15,6 +18,86 @@ const SiteStatus = ({
|
|||||||
emergencyContact,
|
emergencyContact,
|
||||||
lastSyncTimestamp,
|
lastSyncTimestamp,
|
||||||
}: SiteStatusProps) => {
|
}: SiteStatusProps) => {
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const ws = new WebSocket("ws://localhost:8000/ws");
|
||||||
|
|
||||||
|
ws.onmessage = (event) => {
|
||||||
|
const data = event.data;
|
||||||
|
alert(`MQTT: ${data}`);
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.onopen = () => console.log("WebSocket connected");
|
||||||
|
ws.onclose = () => console.log("WebSocket disconnected");
|
||||||
|
|
||||||
|
return () => ws.close();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const [showModal, setShowModal] = useState(false);
|
||||||
|
const [deviceId, setDeviceId] = useState("");
|
||||||
|
const [functionType, setFunctionType] = useState("Grid");
|
||||||
|
|
||||||
|
// Map site names to site IDs
|
||||||
|
const siteIdMap: Record<SiteName, string> = {
|
||||||
|
"Site A": "site_01",
|
||||||
|
"Site B": "site_02",
|
||||||
|
"Site C": "site_03",
|
||||||
|
};
|
||||||
|
|
||||||
|
// Track devices connected per site
|
||||||
|
const [loggedDevices, setLoggedDevices] = useState<Record<string, string[]>>({
|
||||||
|
site_01: [],
|
||||||
|
site_02: [],
|
||||||
|
site_03: [],
|
||||||
|
});
|
||||||
|
|
||||||
|
const siteId = siteIdMap[selectedSite];
|
||||||
|
const devicesAtSite = loggedDevices[siteId] || [];
|
||||||
|
|
||||||
|
const handleStartLogging = () => {
|
||||||
|
setShowModal(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleConfirm = async () => {
|
||||||
|
const siteId = siteIdMap[selectedSite];
|
||||||
|
const topic = `ADW300/${siteId}/${deviceId}/${functionType.toLowerCase()}`;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const response = await axios.post("http://localhost:8000/start-logging", {
|
||||||
|
topics: [topic],
|
||||||
|
});
|
||||||
|
console.log("Started logging:", response.data);
|
||||||
|
|
||||||
|
// Add device to list
|
||||||
|
setLoggedDevices((prev) => ({
|
||||||
|
...prev,
|
||||||
|
[siteId]: [...(prev[siteId] || []), deviceId],
|
||||||
|
}));
|
||||||
|
setShowModal(false);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to start logging:", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleStopLogging = async () => {
|
||||||
|
try {
|
||||||
|
await axios.post("http://localhost:8000/stop-logging");
|
||||||
|
|
||||||
|
// Clear all devices for the site (or modify to remove only specific one)
|
||||||
|
setLoggedDevices((prev) => ({
|
||||||
|
...prev,
|
||||||
|
[siteId]: [],
|
||||||
|
}));
|
||||||
|
|
||||||
|
console.log("Stopped logging for", siteId);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to stop logging:", error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const statusMap: Record<SiteName, string> = {
|
const statusMap: Record<SiteName, string> = {
|
||||||
'Site A': 'Active',
|
'Site A': 'Active',
|
||||||
'Site B': 'Inactive',
|
'Site B': 'Inactive',
|
||||||
@ -37,6 +120,12 @@ const SiteStatus = ({
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Site ID */}
|
||||||
|
<div className="flex justify-between items-center text-base">
|
||||||
|
<p className="text-gray-600 dark:text-gray-400 font-medium">Site ID:</p>
|
||||||
|
<p className="font-medium">{siteId}</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Location */}
|
{/* Location */}
|
||||||
<div className="flex justify-between items-center text-base">
|
<div className="flex justify-between items-center text-base">
|
||||||
<p className="text-gray-600 dark:text-gray-400 font-medium">Location:</p>
|
<p className="text-gray-600 dark:text-gray-400 font-medium">Location:</p>
|
||||||
@ -60,6 +149,67 @@ const SiteStatus = ({
|
|||||||
<p className="text-gray-600 dark:text-gray-400 font-medium">Last Sync:</p>
|
<p className="text-gray-600 dark:text-gray-400 font-medium">Last Sync:</p>
|
||||||
<p className="font-medium">{lastSyncTimestamp}</p>
|
<p className="font-medium">{lastSyncTimestamp}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Start Logging Button */}
|
||||||
|
<div className="flex justify-between items-center text-base space-x-2">
|
||||||
|
{devicesAtSite.length > 0 ? (
|
||||||
|
<button
|
||||||
|
onClick={handleStopLogging}
|
||||||
|
className="text-sm lg:text-md bg-red-500 hover:bg-red-600 text-white font-medium px-3 py-2 rounded"
|
||||||
|
>
|
||||||
|
Stop Logging
|
||||||
|
</button>
|
||||||
|
) : (
|
||||||
|
<button
|
||||||
|
onClick={handleStartLogging}
|
||||||
|
className="text-sm lg:text-md btn-primary px-3 py-2"
|
||||||
|
>
|
||||||
|
Start Logging
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
{/* Modal */}
|
||||||
|
{showModal && (
|
||||||
|
<div className="fixed inset-0 z-50 bg-black bg-opacity-50 flex items-center justify-center">
|
||||||
|
<div className="bg-white rounded-lg p-6 w-[90%] max-w-md shadow-lg">
|
||||||
|
<h2 className="text-lg font-semibold mb-4">Enter Device Info</h2>
|
||||||
|
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
placeholder="Device ID (e.g. device_01)"
|
||||||
|
className="w-full p-2 mb-4 border rounded"
|
||||||
|
value={deviceId}
|
||||||
|
onChange={(e) => setDeviceId(e.target.value)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<select
|
||||||
|
className="w-full p-2 mb-4 border rounded"
|
||||||
|
value={functionType}
|
||||||
|
onChange={(e) => setFunctionType(e.target.value)}
|
||||||
|
>
|
||||||
|
<option value="Grid">Grid</option>
|
||||||
|
<option value="Solar">Solar</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<div className="flex justify-end space-x-2">
|
||||||
|
<button
|
||||||
|
onClick={() => setShowModal(false)}
|
||||||
|
className="btn-primary bg-white border-2 border-black hover:bg-rtgray-200 px-4 py-2"
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
onClick={handleConfirm}
|
||||||
|
className="btn-primary px-4 py-2"
|
||||||
|
>
|
||||||
|
Confirm
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -8,7 +8,7 @@ export interface SiteDetails {
|
|||||||
lastSyncTimestamp: string;
|
lastSyncTimestamp: string;
|
||||||
consumptionData: number[]; // e.g., Daily consumption in kWh
|
consumptionData: number[]; // e.g., Daily consumption in kWh
|
||||||
generationData: number[]; // e.g., Daily generation in kWh
|
generationData: number[]; // e.g., Daily generation in kWh
|
||||||
|
connectedDevices: string[];
|
||||||
// Properties for SystemOverview
|
// Properties for SystemOverview
|
||||||
systemStatus: string; // e.g., "Normal", "Faulty"
|
systemStatus: string; // e.g., "Normal", "Faulty"
|
||||||
temperature: string; // e.g., "35°C"
|
temperature: string; // e.g., "35°C"
|
||||||
@ -56,6 +56,7 @@ export const mockSiteData: Record<SiteName, SiteDetails> = {
|
|||||||
gridImportPrice_RM_per_kWh: 0.50, // Example: RM 0.50 per kWh
|
gridImportPrice_RM_per_kWh: 0.50, // Example: RM 0.50 per kWh
|
||||||
solarExportTariff_RM_per_kWh: 0.30, // Example: RM 0.30 per kWh
|
solarExportTariff_RM_per_kWh: 0.30, // Example: RM 0.30 per kWh
|
||||||
theoreticalMaxGeneration_kWh: 80000, // Example: Theoretical max for 174.9 kWp over a month in Malaysia
|
theoreticalMaxGeneration_kWh: 80000, // Example: Theoretical max for 174.9 kWp over a month in Malaysia
|
||||||
|
connectedDevices : [],
|
||||||
},
|
},
|
||||||
'Site B': {
|
'Site B': {
|
||||||
location: 'Kuala Lumpur, Wilayah Persekutuan',
|
location: 'Kuala Lumpur, Wilayah Persekutuan',
|
||||||
@ -72,6 +73,7 @@ export const mockSiteData: Record<SiteName, SiteDetails> = {
|
|||||||
gridImportPrice_RM_per_kWh: 0.52,
|
gridImportPrice_RM_per_kWh: 0.52,
|
||||||
solarExportTariff_RM_per_kWh: 0.32,
|
solarExportTariff_RM_per_kWh: 0.32,
|
||||||
theoreticalMaxGeneration_kWh: 190000,
|
theoreticalMaxGeneration_kWh: 190000,
|
||||||
|
connectedDevices: [],
|
||||||
},
|
},
|
||||||
'Site C': {
|
'Site C': {
|
||||||
location: 'Johor Bahru, Johor',
|
location: 'Johor Bahru, Johor',
|
||||||
@ -88,5 +90,6 @@ export const mockSiteData: Record<SiteName, SiteDetails> = {
|
|||||||
gridImportPrice_RM_per_kWh: 0.48,
|
gridImportPrice_RM_per_kWh: 0.48,
|
||||||
solarExportTariff_RM_per_kWh: 0.28,
|
solarExportTariff_RM_per_kWh: 0.28,
|
||||||
theoreticalMaxGeneration_kWh: 180000, // Lower theoretical max due to fault or smaller system
|
theoreticalMaxGeneration_kWh: 180000, // Lower theoretical max due to fault or smaller system
|
||||||
|
connectedDevices: [],
|
||||||
},
|
},
|
||||||
};
|
};
|
Loading…
x
Reference in New Issue
Block a user