SRP
This commit is contained in:
@@ -60,6 +60,19 @@
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="setting-group" v-if="simulationModeInput === 'live'">
|
||||
<label>Backend URL (Live Mode)</label>
|
||||
<div class="description">
|
||||
WebSocket server address for real-time updates.
|
||||
</div>
|
||||
<input
|
||||
v-model="backendUrlInput"
|
||||
type="text"
|
||||
placeholder="e.g., http://localhost:8000"
|
||||
class="input-field"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="setting-group">
|
||||
<label>Data Origin (Base URL)</label>
|
||||
<div class="description">
|
||||
@@ -92,8 +105,9 @@ const props = defineProps<{
|
||||
|
||||
const emit = defineEmits(['close']);
|
||||
|
||||
const { state, setDataBaseUrl, setBrightness, setSimulationMode, setMaxZoom, setZoomSensitivity } = useSimulation();
|
||||
const { state, setDataBaseUrl, setBackendUrl, setBrightness, setSimulationMode, setMaxZoom, setZoomSensitivity } = useSimulation();
|
||||
const baseUrlInput = ref('');
|
||||
const backendUrlInput = ref('');
|
||||
const brightnessInput = ref(1.0);
|
||||
const simulationModeInput = ref<'simulated' | 'live'>('simulated');
|
||||
const maxZoomInput = ref(120);
|
||||
@@ -103,6 +117,7 @@ const zoomSensitivityInput = ref(5);
|
||||
watch(() => props.isOpen, (newVal) => {
|
||||
if (newVal) {
|
||||
baseUrlInput.value = state.value.dataBaseUrl || '';
|
||||
backendUrlInput.value = state.value.backendUrl || 'http://localhost:8000';
|
||||
brightnessInput.value = state.value.brightness ?? 1.0;
|
||||
simulationModeInput.value = state.value.simulationMode ?? 'simulated';
|
||||
maxZoomInput.value = state.value.maxZoom ?? 120;
|
||||
@@ -116,6 +131,7 @@ const close = () => {
|
||||
|
||||
const save = () => {
|
||||
setDataBaseUrl(baseUrlInput.value);
|
||||
setBackendUrl(backendUrlInput.value);
|
||||
setBrightness(Number(brightnessInput.value));
|
||||
setSimulationMode(simulationModeInput.value);
|
||||
setMaxZoom(Number(maxZoomInput.value));
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { ref } from 'vue';
|
||||
import Papa from 'papaparse';
|
||||
import { io, type Socket } from 'socket.io-client';
|
||||
|
||||
interface SimulationState {
|
||||
currentTime: number; // 0 to 24 (hours)
|
||||
@@ -10,6 +11,7 @@ interface SimulationState {
|
||||
totalConsumption: number;
|
||||
totalGeneration: number;
|
||||
dataBaseUrl: string;
|
||||
backendUrl: string;
|
||||
brightness: number;
|
||||
simulationMode: 'simulated' | 'live';
|
||||
maxZoom: number;
|
||||
@@ -60,6 +62,7 @@ const state = ref<SimulationState>({
|
||||
totalConsumption: 0,
|
||||
totalGeneration: 0,
|
||||
dataBaseUrl: '',
|
||||
backendUrl: 'http://localhost:8000',
|
||||
brightness: 1.0,
|
||||
simulationMode: 'simulated',
|
||||
maxZoom: 120,
|
||||
@@ -83,6 +86,8 @@ const state = ref<SimulationState>({
|
||||
});
|
||||
const selectedBuilding = ref<BuildingData | null>(null);
|
||||
|
||||
let socket: Socket | null = null;
|
||||
|
||||
export const useSimulation = () => {
|
||||
|
||||
const togglePlay = () => {
|
||||
@@ -97,10 +102,50 @@ export const useSimulation = () => {
|
||||
state.value.brightness = val;
|
||||
};
|
||||
|
||||
const initSocket = () => {
|
||||
if (socket) return;
|
||||
|
||||
console.log(`Connecting to backend: ${state.value.backendUrl}`);
|
||||
socket = io(state.value.backendUrl);
|
||||
|
||||
socket.on('connect', () => {
|
||||
console.log('Socket connected');
|
||||
});
|
||||
|
||||
socket.on('disconnect', () => {
|
||||
console.log('Socket disconnected');
|
||||
});
|
||||
|
||||
socket.on('simulation:update', (data: any) => {
|
||||
// Expected data format: { totalConsumption: number, totalGeneration: number, buildings: { [id]: { consumption: number, generation: number } } }
|
||||
// OR individual updates. Let's assume a snapshot for now or aggregate.
|
||||
// If data contains totals:
|
||||
if (data.totalConsumption !== undefined) state.value.totalConsumption = data.totalConsumption;
|
||||
if (data.totalGeneration !== undefined) state.value.totalGeneration = data.totalGeneration;
|
||||
|
||||
// Update selected building if present
|
||||
if (selectedBuilding.value && data.buildings && data.buildings[selectedBuilding.value.id]) {
|
||||
const bUpdate = data.buildings[selectedBuilding.value.id];
|
||||
selectedBuilding.value.consumption = bUpdate.consumption;
|
||||
selectedBuilding.value.generation = bUpdate.generation;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const disconnectSocket = () => {
|
||||
if (socket) {
|
||||
socket.disconnect();
|
||||
socket = null;
|
||||
}
|
||||
};
|
||||
|
||||
const setSimulationMode = (mode: 'simulated' | 'live') => {
|
||||
state.value.simulationMode = mode;
|
||||
if (mode === 'live') {
|
||||
state.value.isPlaying = true; // Auto-play in live? Or just simple update.
|
||||
initSocket();
|
||||
} else {
|
||||
disconnectSocket();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -116,6 +161,15 @@ export const useSimulation = () => {
|
||||
state.value.dataBaseUrl = url;
|
||||
};
|
||||
|
||||
const setBackendUrl = (url: string) => {
|
||||
state.value.backendUrl = url;
|
||||
// Reconnect if live
|
||||
if (state.value.simulationMode === 'live' && socket) {
|
||||
disconnectSocket();
|
||||
initSocket();
|
||||
}
|
||||
};
|
||||
|
||||
const loadBuildingData = (_buildingId: string, csvPath: string) => {
|
||||
// Construct full URL
|
||||
let fullPath = csvPath;
|
||||
@@ -156,34 +210,34 @@ export const useSimulation = () => {
|
||||
state.value.currentTime = 0;
|
||||
state.value.day++;
|
||||
}
|
||||
}
|
||||
|
||||
// --- Simulated Community Energy Logic ---
|
||||
const time = state.value.currentTime;
|
||||
// --- Simulated Community Energy Logic ---
|
||||
const time = state.value.currentTime;
|
||||
|
||||
// Consumption Curve: Base load + Evening Peak (18-22)
|
||||
// Base Community Load ~4000kW
|
||||
let load = 4000;
|
||||
// Peak
|
||||
if (time > 17 && time < 23) {
|
||||
load += 2000 * Math.sin(((time - 17) / 6) * Math.PI);
|
||||
}
|
||||
// Morning spike
|
||||
if (time > 6 && time < 9) {
|
||||
load += 1000 * Math.sin(((time - 6) / 3) * Math.PI);
|
||||
}
|
||||
// Consumption Curve: Base load + Evening Peak (18-22)
|
||||
// Base Community Load ~4000kW
|
||||
let load = 4000;
|
||||
// Peak
|
||||
if (time > 17 && time < 23) {
|
||||
load += 2000 * Math.sin(((time - 17) / 6) * Math.PI);
|
||||
}
|
||||
// Morning spike
|
||||
if (time > 6 && time < 9) {
|
||||
load += 1000 * Math.sin(((time - 6) / 3) * Math.PI);
|
||||
}
|
||||
|
||||
// Generation Curve: Based on simplified Sun Elevation
|
||||
// Simple Parabola from 6am to 6pm
|
||||
let gen = 0;
|
||||
if (time > 6 && time < 18) {
|
||||
// Peak at 12
|
||||
const sunFactor = Math.sin(((time - 6) / 12) * Math.PI);
|
||||
gen = 3500 * sunFactor; // Max 3500kW generation
|
||||
}
|
||||
// Generation Curve: Based on simplified Sun Elevation
|
||||
// Simple Parabola from 6am to 6pm
|
||||
let gen = 0;
|
||||
if (time > 6 && time < 18) {
|
||||
// Peak at 12
|
||||
const sunFactor = Math.sin(((time - 6) / 12) * Math.PI);
|
||||
gen = 3500 * sunFactor; // Max 3500kW generation
|
||||
}
|
||||
|
||||
state.value.totalConsumption = Math.floor(load);
|
||||
state.value.totalGeneration = Math.floor(gen);
|
||||
state.value.totalConsumption = Math.floor(load);
|
||||
state.value.totalGeneration = Math.floor(gen);
|
||||
}
|
||||
};
|
||||
|
||||
const addBuilding = (def: BuildingDefinition) => {
|
||||
@@ -198,6 +252,7 @@ export const useSimulation = () => {
|
||||
loadBuildingData,
|
||||
updateTime,
|
||||
setDataBaseUrl,
|
||||
setBackendUrl,
|
||||
setBrightness,
|
||||
setSimulationMode,
|
||||
setMaxZoom,
|
||||
|
||||
Reference in New Issue
Block a user