Spaces:
Sleeping
Sleeping
Upload 18 files
Browse files- data.json +954 -0
- documentation_docx/mock_data_documentation.docx +0 -0
- documentation_docx/stability_index_spec.docx +0 -0
- generate_mock_data.py +550 -0
- main.py +418 -64
- output/power/15MIN.csv +385 -0
- output/power/1DAY.csv +5 -0
- output/power/1H.csv +97 -0
- output/power/1MIN.csv +0 -0
- output/power/1SEC.csv +0 -0
- output/stability_index.csv +0 -0
- output/water/15MIN.csv +385 -0
- output/water/1DAY.csv +5 -0
- output/water/1H.csv +97 -0
- output/water/1MIN.csv +0 -0
- requirements.txt +2 -4
- stability_index.py +593 -0
- static/index.html +466 -0
data.json
ADDED
|
@@ -0,0 +1,954 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"description": "Lookup data for the Resource Calculator application, structured for Python integration. All values are per day unless otherwise specified.",
|
| 3 |
+
"inputs": {
|
| 4 |
+
"title": "Trip Configuration",
|
| 5 |
+
"params": {
|
| 6 |
+
"user_type": {
|
| 7 |
+
"label": "User Profile",
|
| 8 |
+
"value": "Glamper",
|
| 9 |
+
"options": [
|
| 10 |
+
"Glamper",
|
| 11 |
+
"Typical",
|
| 12 |
+
"Expert"
|
| 13 |
+
],
|
| 14 |
+
"description": "Defines lifestyle and resource consumption habits."
|
| 15 |
+
},
|
| 16 |
+
"num_people": {
|
| 17 |
+
"label": "Number of People",
|
| 18 |
+
"value": 1,
|
| 19 |
+
"options": [
|
| 20 |
+
1,
|
| 21 |
+
2,
|
| 22 |
+
3,
|
| 23 |
+
4
|
| 24 |
+
],
|
| 25 |
+
"description": "Total number of occupants."
|
| 26 |
+
},
|
| 27 |
+
"trip_duration_days": {
|
| 28 |
+
"label": "Trip Duration",
|
| 29 |
+
"value": 4,
|
| 30 |
+
"unit": "days",
|
| 31 |
+
"description": "Total length of the trip in days."
|
| 32 |
+
},
|
| 33 |
+
"hvac_runtime_hrs": {
|
| 34 |
+
"label": "HVAC Runtime",
|
| 35 |
+
"value": 12,
|
| 36 |
+
"unit": "hrs/day",
|
| 37 |
+
"description": "Daily hours of HVAC operation for climate control and water generation."
|
| 38 |
+
},
|
| 39 |
+
"relocation_count": {
|
| 40 |
+
"label": "Relocation Count",
|
| 41 |
+
"value": 2,
|
| 42 |
+
"description": "Number of times the trailer will be moved to a new campsite during the trip."
|
| 43 |
+
},
|
| 44 |
+
"temperature": {
|
| 45 |
+
"label": "Ambient Temperature",
|
| 46 |
+
"value": "Cold",
|
| 47 |
+
"options": [
|
| 48 |
+
"Hot",
|
| 49 |
+
"Temperate",
|
| 50 |
+
"Cold"
|
| 51 |
+
],
|
| 52 |
+
"description": "Represents seasonal conditions affecting HVAC and solar generation."
|
| 53 |
+
},
|
| 54 |
+
"humidity": {
|
| 55 |
+
"label": "Ambient Humidity",
|
| 56 |
+
"value": "Dry",
|
| 57 |
+
"options": [
|
| 58 |
+
"Humid",
|
| 59 |
+
"Comfortable",
|
| 60 |
+
"Dry"
|
| 61 |
+
],
|
| 62 |
+
"description": "Affects water generation from HVAC and solar panel efficiency."
|
| 63 |
+
},
|
| 64 |
+
"sunlight": {
|
| 65 |
+
"label": "Sunlight Exposure",
|
| 66 |
+
"value": "Lo- Shady",
|
| 67 |
+
"options": [
|
| 68 |
+
"Hi- Sunny",
|
| 69 |
+
"Mid- Cloudy",
|
| 70 |
+
"Lo- Shady"
|
| 71 |
+
],
|
| 72 |
+
"description": "Determines the effectiveness of solar power generation."
|
| 73 |
+
}
|
| 74 |
+
}
|
| 75 |
+
},
|
| 76 |
+
"trailer_specs": {
|
| 77 |
+
"title": "Trailer Specifications",
|
| 78 |
+
"specs": {
|
| 79 |
+
"battery_capacity_kwh": {
|
| 80 |
+
"label": "Battery Capacity",
|
| 81 |
+
"value": 100,
|
| 82 |
+
"unit": "kWh"
|
| 83 |
+
},
|
| 84 |
+
"solar_capacity_kw": {
|
| 85 |
+
"label": "Solar Capacity",
|
| 86 |
+
"value": 5.25,
|
| 87 |
+
"unit": "kW"
|
| 88 |
+
},
|
| 89 |
+
"num_solar_panels": {
|
| 90 |
+
"label": "Number of Solar Panels",
|
| 91 |
+
"value": 35,
|
| 92 |
+
"unit": ""
|
| 93 |
+
},
|
| 94 |
+
"freshwater_capacity_gal": {
|
| 95 |
+
"label": "Freshwater Capacity",
|
| 96 |
+
"value": 100,
|
| 97 |
+
"unit": "gal"
|
| 98 |
+
},
|
| 99 |
+
"blackwater_capacity_gal": {
|
| 100 |
+
"label": "Blackwater Capacity",
|
| 101 |
+
"value": 45,
|
| 102 |
+
"unit": "gal"
|
| 103 |
+
},
|
| 104 |
+
"greywater_capacity_gal": {
|
| 105 |
+
"label": "Greywater Capacity",
|
| 106 |
+
"value": 50,
|
| 107 |
+
"unit": "gal"
|
| 108 |
+
}
|
| 109 |
+
}
|
| 110 |
+
},
|
| 111 |
+
"lookups": {
|
| 112 |
+
"user_profiles": {
|
| 113 |
+
"description": "Usage multipliers based on user profile. From 'User Matrix' sheet.",
|
| 114 |
+
"profiles": {
|
| 115 |
+
"Glamper": {
|
| 116 |
+
"time_based": {
|
| 117 |
+
"mins_per_day": {
|
| 118 |
+
"living_audio": 240,
|
| 119 |
+
"living_tv": 120,
|
| 120 |
+
"living_lighting": 450
|
| 121 |
+
},
|
| 122 |
+
"hrs_per_day": {
|
| 123 |
+
"living_smart_glass": 10,
|
| 124 |
+
"living_electronics": 24,
|
| 125 |
+
"living_party_lighting": 6,
|
| 126 |
+
"living_tire_sensors": 24,
|
| 127 |
+
"living_sensors_controllers": 24,
|
| 128 |
+
"living_security_cameras": 24,
|
| 129 |
+
"living_ext_camp_lights": 4,
|
| 130 |
+
"living_ext_porch_lights": 4,
|
| 131 |
+
"living_smart_tint": 12
|
| 132 |
+
},
|
| 133 |
+
"mins_per_meal": {
|
| 134 |
+
"cooking_stove": 20,
|
| 135 |
+
"cooking_microwave": 5,
|
| 136 |
+
"cooking_garbage_disposal": 1,
|
| 137 |
+
"cooking_consumer_electronics": 8,
|
| 138 |
+
"cooking_water_heater": 4,
|
| 139 |
+
"cooking_pump": 5.585,
|
| 140 |
+
"cooking_range_hood": 22
|
| 141 |
+
},
|
| 142 |
+
"mins_per_cycle": {
|
| 143 |
+
"toilet_pump": 1.13,
|
| 144 |
+
"toilet_vent_fan": 5,
|
| 145 |
+
"toilet_water_heater": 0.33,
|
| 146 |
+
"shower_duration": 10,
|
| 147 |
+
"shower_vent_fan": 20,
|
| 148 |
+
"shower_electronics": 10,
|
| 149 |
+
"shower_water_pump": 10,
|
| 150 |
+
"laundry_water_heater": 30,
|
| 151 |
+
"laundry_water_pump": 30
|
| 152 |
+
}
|
| 153 |
+
},
|
| 154 |
+
"count_based": {
|
| 155 |
+
"cycles_per_day": {
|
| 156 |
+
"living_smart_key": 8
|
| 157 |
+
},
|
| 158 |
+
"meals_per_day": {
|
| 159 |
+
"cooking": 3
|
| 160 |
+
},
|
| 161 |
+
"cycles_per_meal": {
|
| 162 |
+
"cooking_dishwasher": 1
|
| 163 |
+
},
|
| 164 |
+
"cycles_per_day_per_person": {
|
| 165 |
+
"toilet": 7,
|
| 166 |
+
"shower": 1.5,
|
| 167 |
+
"laundry": 0.3333333333
|
| 168 |
+
},
|
| 169 |
+
"burners_per_meal": {
|
| 170 |
+
"cooking_stove": 2
|
| 171 |
+
}
|
| 172 |
+
},
|
| 173 |
+
"volume_based": {
|
| 174 |
+
"gal_per_day": {
|
| 175 |
+
"living_cleaning": 0.75,
|
| 176 |
+
"living_drinking_water": 0.5,
|
| 177 |
+
"living_ice_maker_water": 0.29
|
| 178 |
+
},
|
| 179 |
+
"gal_per_meal": {
|
| 180 |
+
"cooking_dishwasher_water": 3.17,
|
| 181 |
+
"cooking_kitchen_faucet": 2
|
| 182 |
+
},
|
| 183 |
+
"gal_per_cycle": {
|
| 184 |
+
"toilet_sink_water": 0.495,
|
| 185 |
+
"toilet_gravity_flush": 0.4,
|
| 186 |
+
"shower_water": 20
|
| 187 |
+
}
|
| 188 |
+
}
|
| 189 |
+
},
|
| 190 |
+
"Typical": {
|
| 191 |
+
"time_based": {
|
| 192 |
+
"mins_per_day": {
|
| 193 |
+
"living_audio": 120,
|
| 194 |
+
"living_tv": 60,
|
| 195 |
+
"living_lighting": 300
|
| 196 |
+
},
|
| 197 |
+
"hrs_per_day": {
|
| 198 |
+
"living_smart_glass": 6,
|
| 199 |
+
"living_electronics": 16,
|
| 200 |
+
"living_party_lighting": 2.5,
|
| 201 |
+
"living_tire_sensors": 24,
|
| 202 |
+
"living_sensors_controllers": 24,
|
| 203 |
+
"living_security_cameras": 24,
|
| 204 |
+
"living_ext_camp_lights": 2,
|
| 205 |
+
"living_ext_porch_lights": 2,
|
| 206 |
+
"living_smart_tint": 10
|
| 207 |
+
},
|
| 208 |
+
"mins_per_meal": {
|
| 209 |
+
"cooking_stove": 15,
|
| 210 |
+
"cooking_microwave": 3.5,
|
| 211 |
+
"cooking_garbage_disposal": 0.5,
|
| 212 |
+
"cooking_consumer_electronics": 5,
|
| 213 |
+
"cooking_water_heater": 3,
|
| 214 |
+
"cooking_pump": 3.625,
|
| 215 |
+
"cooking_range_hood": 17
|
| 216 |
+
},
|
| 217 |
+
"mins_per_cycle": {
|
| 218 |
+
"toilet_pump": 1.05,
|
| 219 |
+
"toilet_vent_fan": 4,
|
| 220 |
+
"toilet_water_heater": 0.25,
|
| 221 |
+
"shower_duration": 6,
|
| 222 |
+
"shower_vent_fan": 15,
|
| 223 |
+
"shower_electronics": 5,
|
| 224 |
+
"shower_water_pump": 6,
|
| 225 |
+
"laundry_water_heater": 30,
|
| 226 |
+
"laundry_water_pump": 30
|
| 227 |
+
}
|
| 228 |
+
},
|
| 229 |
+
"count_based": {
|
| 230 |
+
"cycles_per_day": {
|
| 231 |
+
"living_smart_key": 4
|
| 232 |
+
},
|
| 233 |
+
"meals_per_day": {
|
| 234 |
+
"cooking": 2
|
| 235 |
+
},
|
| 236 |
+
"cycles_per_meal": {
|
| 237 |
+
"cooking_dishwasher": 0.5
|
| 238 |
+
},
|
| 239 |
+
"cycles_per_day_per_person": {
|
| 240 |
+
"toilet": 5,
|
| 241 |
+
"shower": 1,
|
| 242 |
+
"laundry": 0.2
|
| 243 |
+
},
|
| 244 |
+
"burners_per_meal": {
|
| 245 |
+
"cooking_stove": 1
|
| 246 |
+
}
|
| 247 |
+
},
|
| 248 |
+
"volume_based": {
|
| 249 |
+
"gal_per_day": {
|
| 250 |
+
"living_cleaning": 0.625,
|
| 251 |
+
"living_drinking_water": 0.75,
|
| 252 |
+
"living_ice_maker_water": 0.29
|
| 253 |
+
},
|
| 254 |
+
"gal_per_meal": {
|
| 255 |
+
"cooking_dishwasher_water": 1.25,
|
| 256 |
+
"cooking_kitchen_faucet": 1.5
|
| 257 |
+
},
|
| 258 |
+
"gal_per_cycle": {
|
| 259 |
+
"toilet_sink_water": 0.375,
|
| 260 |
+
"toilet_gravity_flush": 0.4,
|
| 261 |
+
"shower_water": 12
|
| 262 |
+
}
|
| 263 |
+
}
|
| 264 |
+
},
|
| 265 |
+
"Expert": {
|
| 266 |
+
"time_based": {
|
| 267 |
+
"mins_per_day": {
|
| 268 |
+
"living_audio": 10,
|
| 269 |
+
"living_tv": 30,
|
| 270 |
+
"living_lighting": 240
|
| 271 |
+
},
|
| 272 |
+
"hrs_per_day": {
|
| 273 |
+
"living_smart_glass": 3,
|
| 274 |
+
"living_electronics": 10,
|
| 275 |
+
"living_party_lighting": 1,
|
| 276 |
+
"living_tire_sensors": 24,
|
| 277 |
+
"living_sensors_controllers": 24,
|
| 278 |
+
"living_security_cameras": 24,
|
| 279 |
+
"living_ext_camp_lights": 1,
|
| 280 |
+
"living_ext_porch_lights": 1,
|
| 281 |
+
"living_smart_tint": 8
|
| 282 |
+
},
|
| 283 |
+
"mins_per_meal": {
|
| 284 |
+
"cooking_stove": 10,
|
| 285 |
+
"cooking_microwave": 2,
|
| 286 |
+
"cooking_garbage_disposal": 0.1666666667,
|
| 287 |
+
"cooking_consumer_electronics": 3,
|
| 288 |
+
"cooking_water_heater": 1,
|
| 289 |
+
"cooking_pump": 1.4125,
|
| 290 |
+
"cooking_range_hood": 12
|
| 291 |
+
},
|
| 292 |
+
"mins_per_cycle": {
|
| 293 |
+
"toilet_pump": 0.967,
|
| 294 |
+
"toilet_vent_fan": 2.5,
|
| 295 |
+
"toilet_water_heater": 0.167,
|
| 296 |
+
"shower_duration": 3,
|
| 297 |
+
"shower_vent_fan": 10,
|
| 298 |
+
"shower_electronics": 2,
|
| 299 |
+
"shower_water_pump": 3,
|
| 300 |
+
"laundry_water_heater": 30,
|
| 301 |
+
"laundry_water_pump": 30
|
| 302 |
+
}
|
| 303 |
+
},
|
| 304 |
+
"count_based": {
|
| 305 |
+
"cycles_per_day": {
|
| 306 |
+
"living_smart_key": 2
|
| 307 |
+
},
|
| 308 |
+
"meals_per_day": {
|
| 309 |
+
"cooking": 1
|
| 310 |
+
},
|
| 311 |
+
"cycles_per_meal": {
|
| 312 |
+
"cooking_dishwasher": 0.33
|
| 313 |
+
},
|
| 314 |
+
"cycles_per_day_per_person": {
|
| 315 |
+
"toilet": 3,
|
| 316 |
+
"shower": 0.5,
|
| 317 |
+
"laundry": 0.1428571429
|
| 318 |
+
},
|
| 319 |
+
"burners_per_meal": {
|
| 320 |
+
"cooking_stove": 1
|
| 321 |
+
}
|
| 322 |
+
},
|
| 323 |
+
"volume_based": {
|
| 324 |
+
"gal_per_day": {
|
| 325 |
+
"living_cleaning": 0.5,
|
| 326 |
+
"living_drinking_water": 1,
|
| 327 |
+
"living_ice_maker_water": 0.29
|
| 328 |
+
},
|
| 329 |
+
"gal_per_meal": {
|
| 330 |
+
"cooking_dishwasher_water": 0.825,
|
| 331 |
+
"cooking_kitchen_faucet": 0.5
|
| 332 |
+
},
|
| 333 |
+
"gal_per_cycle": {
|
| 334 |
+
"toilet_sink_water": 0.2505,
|
| 335 |
+
"toilet_gravity_flush": 0.4,
|
| 336 |
+
"shower_water": 6
|
| 337 |
+
}
|
| 338 |
+
}
|
| 339 |
+
}
|
| 340 |
+
}
|
| 341 |
+
},
|
| 342 |
+
"components": {
|
| 343 |
+
"schema": [
|
| 344 |
+
"name",
|
| 345 |
+
"voltage_v",
|
| 346 |
+
"avg_amps",
|
| 347 |
+
"water_gal_per_cycle",
|
| 348 |
+
"idle_amps"
|
| 349 |
+
],
|
| 350 |
+
"unit": [
|
| 351 |
+
"",
|
| 352 |
+
"V",
|
| 353 |
+
"A",
|
| 354 |
+
"gal/cycle",
|
| 355 |
+
"A"
|
| 356 |
+
],
|
| 357 |
+
"living": [
|
| 358 |
+
[
|
| 359 |
+
"Audio Amplifier",
|
| 360 |
+
12,
|
| 361 |
+
6,
|
| 362 |
+
0,
|
| 363 |
+
1
|
| 364 |
+
],
|
| 365 |
+
[
|
| 366 |
+
"Television",
|
| 367 |
+
120,
|
| 368 |
+
0.7,
|
| 369 |
+
0,
|
| 370 |
+
0
|
| 371 |
+
],
|
| 372 |
+
[
|
| 373 |
+
"Surround Sound",
|
| 374 |
+
120,
|
| 375 |
+
0.625,
|
| 376 |
+
0,
|
| 377 |
+
0.1317
|
| 378 |
+
],
|
| 379 |
+
[
|
| 380 |
+
"Refrigerator",
|
| 381 |
+
120,
|
| 382 |
+
0.5137,
|
| 383 |
+
0.2857,
|
| 384 |
+
0.5137
|
| 385 |
+
],
|
| 386 |
+
[
|
| 387 |
+
"Satellite Internet PSU",
|
| 388 |
+
12,
|
| 389 |
+
2.5,
|
| 390 |
+
0,
|
| 391 |
+
0
|
| 392 |
+
],
|
| 393 |
+
[
|
| 394 |
+
"Lighting",
|
| 395 |
+
12,
|
| 396 |
+
12,
|
| 397 |
+
0,
|
| 398 |
+
0
|
| 399 |
+
],
|
| 400 |
+
[
|
| 401 |
+
"Tire Pressure Sensors",
|
| 402 |
+
24,
|
| 403 |
+
0.4,
|
| 404 |
+
0,
|
| 405 |
+
0
|
| 406 |
+
],
|
| 407 |
+
[
|
| 408 |
+
"Misc. Sensors & Controllers",
|
| 409 |
+
12,
|
| 410 |
+
0,
|
| 411 |
+
0,
|
| 412 |
+
5
|
| 413 |
+
],
|
| 414 |
+
[
|
| 415 |
+
"Security Cameras",
|
| 416 |
+
12,
|
| 417 |
+
2,
|
| 418 |
+
0,
|
| 419 |
+
0
|
| 420 |
+
],
|
| 421 |
+
[
|
| 422 |
+
"Consumer Electronics",
|
| 423 |
+
120,
|
| 424 |
+
0.5,
|
| 425 |
+
0,
|
| 426 |
+
0
|
| 427 |
+
],
|
| 428 |
+
[
|
| 429 |
+
"Misc. Cleaning",
|
| 430 |
+
0,
|
| 431 |
+
0,
|
| 432 |
+
0.625,
|
| 433 |
+
0
|
| 434 |
+
],
|
| 435 |
+
[
|
| 436 |
+
"Drinking Water Tap",
|
| 437 |
+
0,
|
| 438 |
+
0,
|
| 439 |
+
0.75,
|
| 440 |
+
0
|
| 441 |
+
],
|
| 442 |
+
[
|
| 443 |
+
"Solar Glycol Pump",
|
| 444 |
+
12,
|
| 445 |
+
0.7,
|
| 446 |
+
0,
|
| 447 |
+
0
|
| 448 |
+
],
|
| 449 |
+
[
|
| 450 |
+
"Water Pump",
|
| 451 |
+
12,
|
| 452 |
+
8.5,
|
| 453 |
+
0,
|
| 454 |
+
0
|
| 455 |
+
],
|
| 456 |
+
[
|
| 457 |
+
"UV Water System",
|
| 458 |
+
12,
|
| 459 |
+
1.8,
|
| 460 |
+
0,
|
| 461 |
+
0
|
| 462 |
+
],
|
| 463 |
+
[
|
| 464 |
+
"Tablet UI",
|
| 465 |
+
12,
|
| 466 |
+
0.4167,
|
| 467 |
+
0,
|
| 468 |
+
0
|
| 469 |
+
],
|
| 470 |
+
[
|
| 471 |
+
"SmartTint DC PSU",
|
| 472 |
+
12,
|
| 473 |
+
2.5,
|
| 474 |
+
0,
|
| 475 |
+
0
|
| 476 |
+
],
|
| 477 |
+
[
|
| 478 |
+
"Exterior Camp Lights",
|
| 479 |
+
12,
|
| 480 |
+
0.054,
|
| 481 |
+
0,
|
| 482 |
+
0
|
| 483 |
+
],
|
| 484 |
+
[
|
| 485 |
+
"Exterior Porch Lighting",
|
| 486 |
+
12,
|
| 487 |
+
0.14,
|
| 488 |
+
0,
|
| 489 |
+
0
|
| 490 |
+
],
|
| 491 |
+
[
|
| 492 |
+
"Storage Lights",
|
| 493 |
+
12,
|
| 494 |
+
0.325,
|
| 495 |
+
0,
|
| 496 |
+
0
|
| 497 |
+
],
|
| 498 |
+
[
|
| 499 |
+
"LAN Switch PSU",
|
| 500 |
+
120,
|
| 501 |
+
0.25,
|
| 502 |
+
0,
|
| 503 |
+
0
|
| 504 |
+
],
|
| 505 |
+
[
|
| 506 |
+
"Secure Gateway",
|
| 507 |
+
12,
|
| 508 |
+
0.8333,
|
| 509 |
+
0,
|
| 510 |
+
0.416
|
| 511 |
+
],
|
| 512 |
+
[
|
| 513 |
+
"Telematics T-Box",
|
| 514 |
+
12,
|
| 515 |
+
1.25,
|
| 516 |
+
0,
|
| 517 |
+
0.25
|
| 518 |
+
],
|
| 519 |
+
[
|
| 520 |
+
"4G LTE Antenna",
|
| 521 |
+
12,
|
| 522 |
+
0,
|
| 523 |
+
0,
|
| 524 |
+
0.75
|
| 525 |
+
],
|
| 526 |
+
[
|
| 527 |
+
"Air Purifier",
|
| 528 |
+
120,
|
| 529 |
+
0.375,
|
| 530 |
+
0,
|
| 531 |
+
0
|
| 532 |
+
],
|
| 533 |
+
[
|
| 534 |
+
"AI Compute",
|
| 535 |
+
12,
|
| 536 |
+
20.8333,
|
| 537 |
+
0,
|
| 538 |
+
1.25
|
| 539 |
+
],
|
| 540 |
+
[
|
| 541 |
+
"Party Lighting",
|
| 542 |
+
12,
|
| 543 |
+
18.3333,
|
| 544 |
+
0,
|
| 545 |
+
0
|
| 546 |
+
],
|
| 547 |
+
[
|
| 548 |
+
"Smart Glass Display",
|
| 549 |
+
120,
|
| 550 |
+
0.7167,
|
| 551 |
+
0,
|
| 552 |
+
0.8333
|
| 553 |
+
],
|
| 554 |
+
[
|
| 555 |
+
"Smart Key Lighting",
|
| 556 |
+
12,
|
| 557 |
+
8,
|
| 558 |
+
0,
|
| 559 |
+
0.004
|
| 560 |
+
],
|
| 561 |
+
[
|
| 562 |
+
"Home Assistant Server",
|
| 563 |
+
12,
|
| 564 |
+
12.5,
|
| 565 |
+
0,
|
| 566 |
+
0.004
|
| 567 |
+
],
|
| 568 |
+
[
|
| 569 |
+
"HVAC Controller",
|
| 570 |
+
12,
|
| 571 |
+
7.855,
|
| 572 |
+
0,
|
| 573 |
+
0.01
|
| 574 |
+
],
|
| 575 |
+
[
|
| 576 |
+
"Obstruction Sensors",
|
| 577 |
+
12,
|
| 578 |
+
1,
|
| 579 |
+
0,
|
| 580 |
+
0.01
|
| 581 |
+
]
|
| 582 |
+
],
|
| 583 |
+
"cooking": [
|
| 584 |
+
[
|
| 585 |
+
"Stove",
|
| 586 |
+
240,
|
| 587 |
+
12.5,
|
| 588 |
+
0,
|
| 589 |
+
0
|
| 590 |
+
],
|
| 591 |
+
[
|
| 592 |
+
"Microwave",
|
| 593 |
+
120,
|
| 594 |
+
8.3333,
|
| 595 |
+
0,
|
| 596 |
+
0
|
| 597 |
+
],
|
| 598 |
+
[
|
| 599 |
+
"Dishwasher",
|
| 600 |
+
120,
|
| 601 |
+
5.35,
|
| 602 |
+
1.25,
|
| 603 |
+
0
|
| 604 |
+
],
|
| 605 |
+
[
|
| 606 |
+
"Garbage Disposal",
|
| 607 |
+
120,
|
| 608 |
+
5.6,
|
| 609 |
+
0,
|
| 610 |
+
0
|
| 611 |
+
],
|
| 612 |
+
[
|
| 613 |
+
"Range Hood",
|
| 614 |
+
120,
|
| 615 |
+
3.52,
|
| 616 |
+
0,
|
| 617 |
+
0
|
| 618 |
+
],
|
| 619 |
+
[
|
| 620 |
+
"Consumer Electronics",
|
| 621 |
+
120,
|
| 622 |
+
5,
|
| 623 |
+
0,
|
| 624 |
+
0
|
| 625 |
+
],
|
| 626 |
+
[
|
| 627 |
+
"Tankless Water Heater",
|
| 628 |
+
240,
|
| 629 |
+
33.4,
|
| 630 |
+
0,
|
| 631 |
+
0
|
| 632 |
+
],
|
| 633 |
+
[
|
| 634 |
+
"Water Pump",
|
| 635 |
+
12,
|
| 636 |
+
8.5,
|
| 637 |
+
0,
|
| 638 |
+
0
|
| 639 |
+
],
|
| 640 |
+
[
|
| 641 |
+
"Kitchen Faucet",
|
| 642 |
+
0,
|
| 643 |
+
0,
|
| 644 |
+
1.5,
|
| 645 |
+
0
|
| 646 |
+
]
|
| 647 |
+
],
|
| 648 |
+
"toilet": [
|
| 649 |
+
[
|
| 650 |
+
"Grey Water Pump",
|
| 651 |
+
12,
|
| 652 |
+
2.4,
|
| 653 |
+
0,
|
| 654 |
+
0
|
| 655 |
+
],
|
| 656 |
+
[
|
| 657 |
+
"Bathroom Vent Fan",
|
| 658 |
+
12,
|
| 659 |
+
1.9,
|
| 660 |
+
0,
|
| 661 |
+
0
|
| 662 |
+
],
|
| 663 |
+
[
|
| 664 |
+
"Macerating Pump",
|
| 665 |
+
12,
|
| 666 |
+
17,
|
| 667 |
+
0,
|
| 668 |
+
0
|
| 669 |
+
],
|
| 670 |
+
[
|
| 671 |
+
"Tankless Water Heater",
|
| 672 |
+
240,
|
| 673 |
+
33.4,
|
| 674 |
+
0,
|
| 675 |
+
0
|
| 676 |
+
],
|
| 677 |
+
[
|
| 678 |
+
"Bathroom Sink",
|
| 679 |
+
12,
|
| 680 |
+
1.9,
|
| 681 |
+
0.375,
|
| 682 |
+
0
|
| 683 |
+
]
|
| 684 |
+
],
|
| 685 |
+
"shower": [
|
| 686 |
+
[
|
| 687 |
+
"Electric Shower",
|
| 688 |
+
240,
|
| 689 |
+
33,
|
| 690 |
+
0,
|
| 691 |
+
0
|
| 692 |
+
],
|
| 693 |
+
[
|
| 694 |
+
"Bathroom Vent Fan",
|
| 695 |
+
12,
|
| 696 |
+
1.9,
|
| 697 |
+
0,
|
| 698 |
+
0
|
| 699 |
+
],
|
| 700 |
+
[
|
| 701 |
+
"Consumer Electronics",
|
| 702 |
+
120,
|
| 703 |
+
5,
|
| 704 |
+
0,
|
| 705 |
+
0
|
| 706 |
+
],
|
| 707 |
+
[
|
| 708 |
+
"Water Pump",
|
| 709 |
+
12,
|
| 710 |
+
8.5,
|
| 711 |
+
0,
|
| 712 |
+
0
|
| 713 |
+
]
|
| 714 |
+
],
|
| 715 |
+
"laundry": [
|
| 716 |
+
[
|
| 717 |
+
"Washer/Dryer Combo",
|
| 718 |
+
120,
|
| 719 |
+
15,
|
| 720 |
+
20.6,
|
| 721 |
+
0
|
| 722 |
+
],
|
| 723 |
+
[
|
| 724 |
+
"Tankless Water Heater",
|
| 725 |
+
240,
|
| 726 |
+
33.4,
|
| 727 |
+
0,
|
| 728 |
+
0
|
| 729 |
+
],
|
| 730 |
+
[
|
| 731 |
+
"Water Pump",
|
| 732 |
+
12,
|
| 733 |
+
8.5,
|
| 734 |
+
0,
|
| 735 |
+
0
|
| 736 |
+
]
|
| 737 |
+
],
|
| 738 |
+
"actuation": [
|
| 739 |
+
[
|
| 740 |
+
"Side Room Floor",
|
| 741 |
+
24,
|
| 742 |
+
1.4,
|
| 743 |
+
0,
|
| 744 |
+
0
|
| 745 |
+
],
|
| 746 |
+
[
|
| 747 |
+
"Side Room Wall",
|
| 748 |
+
24,
|
| 749 |
+
1.1,
|
| 750 |
+
0,
|
| 751 |
+
0
|
| 752 |
+
],
|
| 753 |
+
[
|
| 754 |
+
"Front Room",
|
| 755 |
+
24,
|
| 756 |
+
0.427,
|
| 757 |
+
0,
|
| 758 |
+
0
|
| 759 |
+
],
|
| 760 |
+
[
|
| 761 |
+
"Rear Room",
|
| 762 |
+
24,
|
| 763 |
+
0.61,
|
| 764 |
+
0,
|
| 765 |
+
0
|
| 766 |
+
],
|
| 767 |
+
[
|
| 768 |
+
"Chassis Leveling Jacks",
|
| 769 |
+
24,
|
| 770 |
+
9.3,
|
| 771 |
+
0,
|
| 772 |
+
0
|
| 773 |
+
],
|
| 774 |
+
[
|
| 775 |
+
"Room Support Jacks",
|
| 776 |
+
12,
|
| 777 |
+
15,
|
| 778 |
+
0,
|
| 779 |
+
0
|
| 780 |
+
],
|
| 781 |
+
[
|
| 782 |
+
"Gearage",
|
| 783 |
+
24,
|
| 784 |
+
0.13,
|
| 785 |
+
0,
|
| 786 |
+
0
|
| 787 |
+
],
|
| 788 |
+
[
|
| 789 |
+
"Awning",
|
| 790 |
+
12,
|
| 791 |
+
10,
|
| 792 |
+
0,
|
| 793 |
+
0
|
| 794 |
+
],
|
| 795 |
+
[
|
| 796 |
+
"Furniture Automation",
|
| 797 |
+
120,
|
| 798 |
+
10,
|
| 799 |
+
0,
|
| 800 |
+
0
|
| 801 |
+
],
|
| 802 |
+
[
|
| 803 |
+
"TV Rise",
|
| 804 |
+
120,
|
| 805 |
+
3.5,
|
| 806 |
+
0,
|
| 807 |
+
0
|
| 808 |
+
],
|
| 809 |
+
[
|
| 810 |
+
"Electric Tongue Jack",
|
| 811 |
+
12,
|
| 812 |
+
30,
|
| 813 |
+
0,
|
| 814 |
+
0
|
| 815 |
+
],
|
| 816 |
+
[
|
| 817 |
+
"Motor Controllers",
|
| 818 |
+
12,
|
| 819 |
+
1.25,
|
| 820 |
+
0,
|
| 821 |
+
0
|
| 822 |
+
]
|
| 823 |
+
],
|
| 824 |
+
"dumping": [
|
| 825 |
+
[
|
| 826 |
+
"Electric Waste Valves",
|
| 827 |
+
12,
|
| 828 |
+
2.5,
|
| 829 |
+
0,
|
| 830 |
+
0
|
| 831 |
+
]
|
| 832 |
+
],
|
| 833 |
+
"hvac": [
|
| 834 |
+
[
|
| 835 |
+
"Mini-Split HVAC (Hot/Cold)",
|
| 836 |
+
240,
|
| 837 |
+
9.205,
|
| 838 |
+
0,
|
| 839 |
+
0
|
| 840 |
+
],
|
| 841 |
+
[
|
| 842 |
+
"Mini-Split HVAC (Temperate)",
|
| 843 |
+
240,
|
| 844 |
+
4.082,
|
| 845 |
+
0,
|
| 846 |
+
0
|
| 847 |
+
]
|
| 848 |
+
]
|
| 849 |
+
},
|
| 850 |
+
"hvac_energy_wh_day": {
|
| 851 |
+
"Hot": 6923.75,
|
| 852 |
+
"Temperate": 744.68,
|
| 853 |
+
"Cold": 15615.35
|
| 854 |
+
},
|
| 855 |
+
"hvac_water_gen_gph": {
|
| 856 |
+
"day": {
|
| 857 |
+
"Hot": {
|
| 858 |
+
"Humid": 0,
|
| 859 |
+
"Comfortable": 0,
|
| 860 |
+
"Dry": 0
|
| 861 |
+
},
|
| 862 |
+
"Temperate": {
|
| 863 |
+
"Humid": 0,
|
| 864 |
+
"Comfortable": 0,
|
| 865 |
+
"Dry": 0
|
| 866 |
+
},
|
| 867 |
+
"Cold": {
|
| 868 |
+
"Humid": 0,
|
| 869 |
+
"Comfortable": 0,
|
| 870 |
+
"Dry": 0
|
| 871 |
+
}
|
| 872 |
+
},
|
| 873 |
+
"night": {
|
| 874 |
+
"Hot": {
|
| 875 |
+
"Humid": 0,
|
| 876 |
+
"Comfortable": 0,
|
| 877 |
+
"Dry": 0
|
| 878 |
+
},
|
| 879 |
+
"Temperate": {
|
| 880 |
+
"Humid": 0,
|
| 881 |
+
"Comfortable": 0,
|
| 882 |
+
"Dry": 0
|
| 883 |
+
},
|
| 884 |
+
"Cold": {
|
| 885 |
+
"Humid": 0,
|
| 886 |
+
"Comfortable": 0,
|
| 887 |
+
"Dry": 0
|
| 888 |
+
}
|
| 889 |
+
}
|
| 890 |
+
},
|
| 891 |
+
"waste_production": {
|
| 892 |
+
"description": "Values are per day for Living, and per cycle for others.",
|
| 893 |
+
"unit": "gal",
|
| 894 |
+
"living_cleaning": {
|
| 895 |
+
"grey": 0.625,
|
| 896 |
+
"black": 0
|
| 897 |
+
},
|
| 898 |
+
"cooking_dishwasher": {
|
| 899 |
+
"grey": 1.25,
|
| 900 |
+
"black": 0
|
| 901 |
+
},
|
| 902 |
+
"cooking_sink": {
|
| 903 |
+
"grey": 0,
|
| 904 |
+
"black": 1.125
|
| 905 |
+
},
|
| 906 |
+
"shower": {
|
| 907 |
+
"grey": 12,
|
| 908 |
+
"black": 0
|
| 909 |
+
},
|
| 910 |
+
"laundry": {
|
| 911 |
+
"grey": 4.12,
|
| 912 |
+
"black": 0
|
| 913 |
+
},
|
| 914 |
+
"toilet_handwashing": {
|
| 915 |
+
"grey": 0.375,
|
| 916 |
+
"black": 0
|
| 917 |
+
},
|
| 918 |
+
"toilet_flush": {
|
| 919 |
+
"grey": -0.4,
|
| 920 |
+
"black": 0.4
|
| 921 |
+
}
|
| 922 |
+
},
|
| 923 |
+
"solar": {
|
| 924 |
+
"system_loss_factor": 0.9,
|
| 925 |
+
"tilt_factor": {
|
| 926 |
+
"Hot": 0.8,
|
| 927 |
+
"Temperate": 0.8,
|
| 928 |
+
"Cold": 0.75
|
| 929 |
+
},
|
| 930 |
+
"sunlight_factor": {
|
| 931 |
+
"Hi- Sunny": 1.0,
|
| 932 |
+
"Mid- Cloudy": 0.5,
|
| 933 |
+
"Lo- Shady": 0.25
|
| 934 |
+
},
|
| 935 |
+
"insolation_wh_m2_day": {
|
| 936 |
+
"Hot": {
|
| 937 |
+
"Dry": 10022,
|
| 938 |
+
"Comfortable": 9514,
|
| 939 |
+
"Humid": 7526
|
| 940 |
+
},
|
| 941 |
+
"Temperate": {
|
| 942 |
+
"Dry": 7231,
|
| 943 |
+
"Comfortable": 6821,
|
| 944 |
+
"Humid": 5340
|
| 945 |
+
},
|
| 946 |
+
"Cold": {
|
| 947 |
+
"Dry": 3758,
|
| 948 |
+
"Comfortable": 3532,
|
| 949 |
+
"Humid": 2604
|
| 950 |
+
}
|
| 951 |
+
}
|
| 952 |
+
}
|
| 953 |
+
}
|
| 954 |
+
}
|
documentation_docx/mock_data_documentation.docx
ADDED
|
Binary file (23.2 kB). View file
|
|
|
documentation_docx/stability_index_spec.docx
ADDED
|
Binary file (20.9 kB). View file
|
|
|
generate_mock_data.py
ADDED
|
@@ -0,0 +1,550 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
EV Camper Mock Data Generator
|
| 3 |
+
==============================
|
| 4 |
+
Generates realistic power and water CSV exports following the discussed schema,
|
| 5 |
+
derived from data.json lookup tables.
|
| 6 |
+
|
| 7 |
+
Column naming convention:
|
| 8 |
+
*_kW instantaneous power (flow files: 1SEC, 1MIN, 15MIN)
|
| 9 |
+
*_kWh accumulated energy (energy files: 1H, 1DAY)
|
| 10 |
+
*_V voltage (instantaneous or averaged)
|
| 11 |
+
*_Ah amp-hours (battery state snapshot)
|
| 12 |
+
*_Pct percentage (battery / tank level)
|
| 13 |
+
*_Lpm litres per minute (water flow files: 1MIN, 15MIN)
|
| 14 |
+
*_L litres (water energy files: 1H, 1DAY, and tank level snapshots)
|
| 15 |
+
|
| 16 |
+
Output ZIP contains:
|
| 17 |
+
power/ -> 1SEC.csv, 1MIN.csv, 15MIN.csv, 1H.csv, 1DAY.csv
|
| 18 |
+
water/ -> 1MIN.csv, 15MIN.csv, 1H.csv, 1DAY.csv
|
| 19 |
+
|
| 20 |
+
Usage:
|
| 21 |
+
python generate_mock_data.py [--config data.json] [--out output] [--seed 42]
|
| 22 |
+
python generate_mock_data.py --user Glamper --people 2 --days 5 --temp Hot
|
| 23 |
+
"""
|
| 24 |
+
|
| 25 |
+
import json
|
| 26 |
+
import csv
|
| 27 |
+
import os
|
| 28 |
+
import math
|
| 29 |
+
import random
|
| 30 |
+
import zipfile
|
| 31 |
+
import argparse
|
| 32 |
+
from datetime import datetime, timedelta
|
| 33 |
+
from pathlib import Path
|
| 34 |
+
|
| 35 |
+
|
| 36 |
+
# ---------------------------------------------------------------------------
|
| 37 |
+
# CONSTANTS
|
| 38 |
+
# ---------------------------------------------------------------------------
|
| 39 |
+
|
| 40 |
+
GAL_TO_LITRES = 3.78541
|
| 41 |
+
MINS_PER_DAY = 1440
|
| 42 |
+
SOLAR_PANEL_AREA_M2 = 1.8 # ~330W panel footprint
|
| 43 |
+
BATTERY_NOMINAL_V = 48.0 # for kWh <-> Ah conversion
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
# ---------------------------------------------------------------------------
|
| 47 |
+
# DATA LOADER
|
| 48 |
+
# ---------------------------------------------------------------------------
|
| 49 |
+
|
| 50 |
+
def load_data(path: str) -> dict:
|
| 51 |
+
with open(path) as f:
|
| 52 |
+
return json.load(f)
|
| 53 |
+
|
| 54 |
+
|
| 55 |
+
# ---------------------------------------------------------------------------
|
| 56 |
+
# DAILY BUDGET CALCULATORS
|
| 57 |
+
# ---------------------------------------------------------------------------
|
| 58 |
+
|
| 59 |
+
def calc_power_budget(data: dict, user: str, people: int,
|
| 60 |
+
temp: str, hvac_hrs: float) -> dict:
|
| 61 |
+
"""
|
| 62 |
+
Returns expected kWh per day broken down by circuit + solar generation.
|
| 63 |
+
Derived from component voltage x amps tables and user profile runtimes.
|
| 64 |
+
"""
|
| 65 |
+
p = data["lookups"]["user_profiles"]["profiles"][user]
|
| 66 |
+
tb = p["time_based"]
|
| 67 |
+
cb = p["count_based"]
|
| 68 |
+
|
| 69 |
+
def watts(v, a): return v * a
|
| 70 |
+
|
| 71 |
+
# HVAC
|
| 72 |
+
hvac_kwh = data["lookups"]["hvac_energy_wh_day"][temp] / 1000.0
|
| 73 |
+
|
| 74 |
+
# Lighting (12V 12A)
|
| 75 |
+
lighting_kwh = watts(12, 12) * (tb["mins_per_day"].get("living_lighting", 300) / 60) / 1000
|
| 76 |
+
|
| 77 |
+
# Devices: always-on sensors/compute + active electronics
|
| 78 |
+
devices_kwh = (
|
| 79 |
+
5 * 12 * 24 # sensor idle
|
| 80 |
+
+ 1.25 * 12 * 24 # compute idle
|
| 81 |
+
+ 0.5 * 120 * tb["hrs_per_day"].get("living_electronics", 16)
|
| 82 |
+
) / 1000
|
| 83 |
+
|
| 84 |
+
# Fridge (24h)
|
| 85 |
+
fridge_kwh = watts(120, 0.5137) * 24 / 1000
|
| 86 |
+
|
| 87 |
+
# Water pump
|
| 88 |
+
meals = cb["meals_per_day"]["cooking"]
|
| 89 |
+
shower_cyc = cb["cycles_per_day_per_person"]["shower"] * people
|
| 90 |
+
toilet_cyc = cb["cycles_per_day_per_person"]["toilet"] * people
|
| 91 |
+
pump_mins = (tb["mins_per_meal"].get("cooking_pump", 3.625) * meals
|
| 92 |
+
+ tb["mins_per_cycle"].get("shower_water_pump", 6) * shower_cyc
|
| 93 |
+
+ 1.0 * toilet_cyc)
|
| 94 |
+
water_pump_kwh = watts(12, 8.5) * (pump_mins / 60) / 1000
|
| 95 |
+
|
| 96 |
+
# Cooking (stove + microwave + water heater)
|
| 97 |
+
cooking_kwh = (
|
| 98 |
+
watts(240, 12.5) * (tb["mins_per_meal"].get("cooking_stove", 15) * meals / 60)
|
| 99 |
+
+ watts(120, 8.333) * (tb["mins_per_meal"].get("cooking_microwave", 3.5) * meals / 60)
|
| 100 |
+
+ watts(240, 33.4) * ((tb["mins_per_meal"].get("cooking_water_heater", 3) * meals
|
| 101 |
+
+ tb["mins_per_cycle"].get("shower_duration", 6) * shower_cyc) / 60)
|
| 102 |
+
) / 1000
|
| 103 |
+
|
| 104 |
+
# Inverter load (TV as representative AC load)
|
| 105 |
+
inverter_kwh = watts(120, 0.7) * (tb["mins_per_day"].get("living_tv", 60) / 60) / 1000
|
| 106 |
+
|
| 107 |
+
# Solar generation
|
| 108 |
+
sol = data["lookups"]["solar"]
|
| 109 |
+
humidity = data["inputs"]["params"]["humidity"]["value"]
|
| 110 |
+
sunlight = data["inputs"]["params"]["sunlight"]["value"]
|
| 111 |
+
insolation = sol["insolation_wh_m2_day"][temp][humidity]
|
| 112 |
+
num_panels = (data["trailer_specs"]["specs"]["num_solar_panels"]["value"]
|
| 113 |
+
if "num_solar_panels" in data["trailer_specs"]["specs"] else 35)
|
| 114 |
+
solar_kwh = (insolation * num_panels * SOLAR_PANEL_AREA_M2
|
| 115 |
+
* sol["system_loss_factor"]
|
| 116 |
+
* sol["tilt_factor"][temp]
|
| 117 |
+
* sol["sunlight_factor"][sunlight]) / 1_000
|
| 118 |
+
solar_kwh = min(solar_kwh,
|
| 119 |
+
data["trailer_specs"]["specs"]["solar_capacity_kw"]["value"] * 6)
|
| 120 |
+
|
| 121 |
+
return {
|
| 122 |
+
"solar_kwh": round(solar_kwh, 3),
|
| 123 |
+
"hvac_kwh": round(hvac_kwh, 3),
|
| 124 |
+
"lighting_kwh": round(lighting_kwh, 3),
|
| 125 |
+
"devices_kwh": round(devices_kwh, 3),
|
| 126 |
+
"fridge_kwh": round(fridge_kwh, 3),
|
| 127 |
+
"water_pump_kwh": round(water_pump_kwh, 3),
|
| 128 |
+
"cooking_kwh": round(cooking_kwh, 3),
|
| 129 |
+
"inverter_kwh": round(inverter_kwh, 3),
|
| 130 |
+
}
|
| 131 |
+
|
| 132 |
+
|
| 133 |
+
def calc_water_budget(data: dict, user: str, people: int) -> dict:
|
| 134 |
+
"""Returns expected litres per day per circuit, converted from profile gallon tables."""
|
| 135 |
+
p = data["lookups"]["user_profiles"]["profiles"][user]
|
| 136 |
+
vb = p["volume_based"]
|
| 137 |
+
cb = p["count_based"]
|
| 138 |
+
|
| 139 |
+
meals = cb["meals_per_day"]["cooking"]
|
| 140 |
+
shower_cyc = cb["cycles_per_day_per_person"]["shower"] * people
|
| 141 |
+
toilet_cyc = cb["cycles_per_day_per_person"]["toilet"] * people
|
| 142 |
+
|
| 143 |
+
def g2l(g): return round(g * GAL_TO_LITRES, 3)
|
| 144 |
+
|
| 145 |
+
return {
|
| 146 |
+
"shower_L": g2l(vb["gal_per_cycle"]["shower_water"] * shower_cyc),
|
| 147 |
+
"toilet_L": g2l((vb["gal_per_cycle"]["toilet_sink_water"]
|
| 148 |
+
+ vb["gal_per_cycle"]["toilet_gravity_flush"]) * toilet_cyc),
|
| 149 |
+
"kitchen_L": g2l((vb["gal_per_meal"].get("cooking_kitchen_faucet", 1.5)
|
| 150 |
+
+ vb["gal_per_meal"].get("cooking_dishwasher_water", 1.25)) * meals
|
| 151 |
+
+ vb["gal_per_day"].get("living_cleaning", 0.625)
|
| 152 |
+
+ vb["gal_per_day"].get("living_drinking_water", 0.75) * people),
|
| 153 |
+
}
|
| 154 |
+
|
| 155 |
+
|
| 156 |
+
# ---------------------------------------------------------------------------
|
| 157 |
+
# TIME-OF-DAY SHAPE FUNCTIONS
|
| 158 |
+
# ---------------------------------------------------------------------------
|
| 159 |
+
|
| 160 |
+
def solar_curve(hour: float) -> float:
|
| 161 |
+
if hour < 6 or hour > 18:
|
| 162 |
+
return 0.0
|
| 163 |
+
return max(0.0, math.sin(math.pi * (hour - 6) / 12))
|
| 164 |
+
|
| 165 |
+
def activity_curve(hour: float) -> float:
|
| 166 |
+
return max(0.01,
|
| 167 |
+
math.exp(-0.5 * ((hour - 8.0) / 1.2) ** 2)
|
| 168 |
+
+ math.exp(-0.5 * ((hour - 19.5) / 1.5) ** 2) * 0.8)
|
| 169 |
+
|
| 170 |
+
def hvac_curve(hour: float, temp: str) -> float:
|
| 171 |
+
if temp == "Hot":
|
| 172 |
+
return (0.4 + 0.6 * math.sin(math.pi * max(0, hour - 9) / 12)
|
| 173 |
+
if 9 <= hour <= 21 else 0.2)
|
| 174 |
+
if temp == "Cold":
|
| 175 |
+
return 0.7 + 0.3 * (1 - solar_curve(hour))
|
| 176 |
+
return 0.4 + 0.1 * math.sin(math.pi * hour / 24)
|
| 177 |
+
|
| 178 |
+
def water_event_curve(hour: float) -> float:
|
| 179 |
+
return max(0.0,
|
| 180 |
+
math.exp(-0.5 * ((hour - 7.5) / 1.0) ** 2)
|
| 181 |
+
+ math.exp(-0.5 * ((hour - 19.0) / 1.0) ** 2) * 0.6)
|
| 182 |
+
|
| 183 |
+
def jitter(rng: random.Random, scale: float = 0.05) -> float:
|
| 184 |
+
return 1.0 + rng.gauss(0, scale)
|
| 185 |
+
|
| 186 |
+
|
| 187 |
+
# ---------------------------------------------------------------------------
|
| 188 |
+
# MINUTE-LEVEL SERIES BUILDERS
|
| 189 |
+
# ---------------------------------------------------------------------------
|
| 190 |
+
|
| 191 |
+
def build_power_minutes(budget: dict, temp: str, battery_cap_kwh: float,
|
| 192 |
+
start: datetime, num_days: int,
|
| 193 |
+
rng: random.Random) -> list[dict]:
|
| 194 |
+
"""
|
| 195 |
+
1-minute power rows.
|
| 196 |
+
Flow columns: *_kW | State columns: *_Ah, *_Pct, *_V
|
| 197 |
+
"""
|
| 198 |
+
solar_cap_kw = budget["solar_kwh"] / 6.0
|
| 199 |
+
hvac_mean = budget["hvac_kwh"] / 24
|
| 200 |
+
lighting_mean = budget["lighting_kwh"] / (300 / 60)
|
| 201 |
+
devices_mean = budget["devices_kwh"] / 24
|
| 202 |
+
fridge_mean = budget["fridge_kwh"] / 24
|
| 203 |
+
pump_mean = budget["water_pump_kwh"] / 2
|
| 204 |
+
cooking_mean = budget["cooking_kwh"] / 1.5
|
| 205 |
+
inverter_mean = budget["inverter_kwh"] / max(budget["inverter_kwh"] / (0.7 * 120 / 1000), 0.1)
|
| 206 |
+
|
| 207 |
+
battery_kwh = battery_cap_kwh * 0.80
|
| 208 |
+
rows = []
|
| 209 |
+
|
| 210 |
+
for m in range(num_days * MINS_PER_DAY):
|
| 211 |
+
ts = start + timedelta(minutes=m)
|
| 212 |
+
hour = ts.hour + ts.minute / 60.0
|
| 213 |
+
|
| 214 |
+
solar_kw = round(max(0, solar_cap_kw * solar_curve(hour) * rng.uniform(0.85, 1.05)), 4)
|
| 215 |
+
ac = activity_curve(hour)
|
| 216 |
+
|
| 217 |
+
hvac_kw = round(max(0, hvac_mean * hvac_curve(hour, temp) * jitter(rng, 0.08)), 4)
|
| 218 |
+
lighting_kw = round((max(0, lighting_mean * ac * jitter(rng, 0.05)) if 6 <= hour <= 23 else 0.002), 4)
|
| 219 |
+
devices_kw = round(max(0, devices_mean * jitter(rng, 0.04)), 4)
|
| 220 |
+
fridge_kw = round(max(0, fridge_mean * (0.7 + 0.6 * rng.random()) * jitter(rng, 0.03)), 4)
|
| 221 |
+
pump_kw = round(max(0, pump_mean * water_event_curve(hour) * jitter(rng, 0.15)), 4)
|
| 222 |
+
cooking_kw = round(max(0, cooking_mean * ac * jitter(rng, 0.20)) if ac > 0.3 else 0.0, 4)
|
| 223 |
+
inverter_kw = round(max(0, inverter_mean * ac * jitter(rng, 0.10)), 4)
|
| 224 |
+
|
| 225 |
+
total_load = hvac_kw + lighting_kw + devices_kw + fridge_kw + pump_kw + cooking_kw + inverter_kw
|
| 226 |
+
net = solar_kw - total_load
|
| 227 |
+
shore_kw = 0.0
|
| 228 |
+
|
| 229 |
+
if net < 0 and battery_kwh < abs(net) / 60 * 0.95:
|
| 230 |
+
shore_kw = round(abs(net) * 1.05, 4)
|
| 231 |
+
net = 0.0
|
| 232 |
+
|
| 233 |
+
battery_flow_kw = round(net, 4)
|
| 234 |
+
battery_kwh = max(0, min(battery_cap_kwh, battery_kwh + battery_flow_kw / 60))
|
| 235 |
+
|
| 236 |
+
unmetered_kw = round(max(0,
|
| 237 |
+
solar_kw + shore_kw
|
| 238 |
+
+ (abs(battery_flow_kw) if battery_flow_kw < 0 else 0)
|
| 239 |
+
- total_load
|
| 240 |
+
- (battery_flow_kw if battery_flow_kw > 0 else 0)
|
| 241 |
+
), 4)
|
| 242 |
+
|
| 243 |
+
rows.append({
|
| 244 |
+
"Time": ts.strftime("%Y-%m-%dT%H:%M:%SZ"),
|
| 245 |
+
"Solar_Flow_kW": solar_kw,
|
| 246 |
+
"Shore_Flow_kW": shore_kw,
|
| 247 |
+
"Battery_Flow_kW": battery_flow_kw,
|
| 248 |
+
"HVAC_Flow_kW": hvac_kw,
|
| 249 |
+
"Lighting_Flow_kW": lighting_kw,
|
| 250 |
+
"Devices_Flow_kW": devices_kw,
|
| 251 |
+
"Fridge_Flow_kW": fridge_kw,
|
| 252 |
+
"WaterPump_Flow_kW": pump_kw,
|
| 253 |
+
"Cooking_Flow_kW": cooking_kw,
|
| 254 |
+
"Inverter_Flow_kW": inverter_kw,
|
| 255 |
+
"Unmetered_Flow_kW": unmetered_kw,
|
| 256 |
+
"Battery_Level_Ah": round(battery_kwh * 1000 / BATTERY_NOMINAL_V, 1),
|
| 257 |
+
"Battery_Level_Pct": round(battery_kwh / battery_cap_kwh * 100, 2),
|
| 258 |
+
"Solar_Voltage_V": round(rng.uniform(36, 52) if solar_kw > 0 else 0.0, 1),
|
| 259 |
+
"Battery_Voltage_V": round(46 + (battery_kwh / battery_cap_kwh) * 6 + rng.gauss(0, 0.2), 2),
|
| 260 |
+
})
|
| 261 |
+
|
| 262 |
+
return rows
|
| 263 |
+
|
| 264 |
+
|
| 265 |
+
def build_water_minutes(budget: dict, fresh_cap_L: float, grey_cap_L: float,
|
| 266 |
+
black_cap_L: float,
|
| 267 |
+
start: datetime, num_days: int,
|
| 268 |
+
rng: random.Random) -> list[dict]:
|
| 269 |
+
"""
|
| 270 |
+
1-minute water rows.
|
| 271 |
+
Flow columns: *_Lpm | State columns: *_L
|
| 272 |
+
|
| 273 |
+
Black tank level is derived entirely from Toilet_Flow_Lpm:
|
| 274 |
+
100% of toilet flush volume enters the black tank.
|
| 275 |
+
Grey tank receives shower + kitchen waste only (90% of flow, 10% evaporation/splash).
|
| 276 |
+
"""
|
| 277 |
+
shower_rate = budget["shower_L"] / MINS_PER_DAY
|
| 278 |
+
toilet_rate = budget["toilet_L"] / MINS_PER_DAY
|
| 279 |
+
kitchen_rate = budget["kitchen_L"] / MINS_PER_DAY
|
| 280 |
+
|
| 281 |
+
fresh_L = fresh_cap_L * 0.95
|
| 282 |
+
grey_L = 0.0
|
| 283 |
+
black_L = 0.0 # starts empty; fills from toilet flow
|
| 284 |
+
rows = []
|
| 285 |
+
|
| 286 |
+
for m in range(num_days * MINS_PER_DAY):
|
| 287 |
+
ts = start + timedelta(minutes=m)
|
| 288 |
+
hour = ts.hour + ts.minute / 60.0
|
| 289 |
+
wc = water_event_curve(hour)
|
| 290 |
+
|
| 291 |
+
# Tank-fill event at 07:00 on day 1 only
|
| 292 |
+
inlet_Lpm = round(rng.uniform(8, 12), 3) if m == 420 else 0.0
|
| 293 |
+
|
| 294 |
+
shower_Lpm = round(max(0, shower_rate * wc * 2.5 * jitter(rng, 0.15)), 4)
|
| 295 |
+
kitchen_Lpm = round(max(0, kitchen_rate * wc * 2.0 * jitter(rng, 0.10)), 4)
|
| 296 |
+
toilet_Lpm = round(max(0, toilet_rate * wc * 2.0 * jitter(rng, 0.20)), 4)
|
| 297 |
+
pump_Lpm = shower_Lpm + kitchen_Lpm + toilet_Lpm
|
| 298 |
+
|
| 299 |
+
if fresh_L < pump_Lpm:
|
| 300 |
+
pump_Lpm = max(0, fresh_L)
|
| 301 |
+
shower_Lpm = round(pump_Lpm * 0.60, 4)
|
| 302 |
+
kitchen_Lpm = round(pump_Lpm * 0.25, 4)
|
| 303 |
+
toilet_Lpm = round(pump_Lpm * 0.15, 4)
|
| 304 |
+
|
| 305 |
+
unmetered_Lpm = round(max(0, pump_Lpm - shower_Lpm - kitchen_Lpm - toilet_Lpm), 4)
|
| 306 |
+
|
| 307 |
+
# Update tank levels
|
| 308 |
+
fresh_L = max(0, min(fresh_cap_L, fresh_L + inlet_Lpm - pump_Lpm))
|
| 309 |
+
grey_L = min(grey_cap_L, grey_L + (shower_Lpm + kitchen_Lpm) * 0.9)
|
| 310 |
+
black_L = min(black_cap_L, black_L + toilet_Lpm) # 100% of toilet β black tank
|
| 311 |
+
|
| 312 |
+
rows.append({
|
| 313 |
+
"Time": ts.strftime("%Y-%m-%dT%H:%M:%SZ"),
|
| 314 |
+
"Inlet_Flow_Lpm": inlet_Lpm,
|
| 315 |
+
"Pump_Flow_Lpm": round(pump_Lpm, 4),
|
| 316 |
+
"Shower_Flow_Lpm": shower_Lpm,
|
| 317 |
+
"Kitchen_Flow_Lpm": kitchen_Lpm,
|
| 318 |
+
"Toilet_Flow_Lpm": toilet_Lpm,
|
| 319 |
+
"Unmetered_Flow_Lpm": unmetered_Lpm,
|
| 320 |
+
"FreshTank_Level_L": round(fresh_L, 2),
|
| 321 |
+
"GreyTank_Level_L": round(grey_L, 2),
|
| 322 |
+
"BlackTank_Level_L": round(black_L, 2),
|
| 323 |
+
})
|
| 324 |
+
|
| 325 |
+
return rows
|
| 326 |
+
|
| 327 |
+
|
| 328 |
+
# ---------------------------------------------------------------------------
|
| 329 |
+
# RESAMPLING
|
| 330 |
+
# ---------------------------------------------------------------------------
|
| 331 |
+
|
| 332 |
+
def resample_power(rows: list[dict], interval_mins: int, mode: str = "mean") -> list[dict]:
|
| 333 |
+
"""
|
| 334 |
+
mode='mean' β kW (15MIN flow file)
|
| 335 |
+
mode='sum' β kWh (1H, 1DAY energy files) [kW Γ 1 min / 60 = kWh]
|
| 336 |
+
"""
|
| 337 |
+
CIRCUITS = ["HVAC", "Lighting", "Devices", "Fridge",
|
| 338 |
+
"WaterPump", "Cooking", "Inverter", "Unmetered"]
|
| 339 |
+
out = []
|
| 340 |
+
|
| 341 |
+
for i in range(0, len(rows), interval_mins):
|
| 342 |
+
bucket = rows[i: i + interval_mins]
|
| 343 |
+
if not bucket:
|
| 344 |
+
continue
|
| 345 |
+
first, last = bucket[0], bucket[-1]
|
| 346 |
+
|
| 347 |
+
def mean(col):
|
| 348 |
+
return round(sum(r[col] for r in bucket) / len(bucket), 4)
|
| 349 |
+
|
| 350 |
+
def to_kwh(col):
|
| 351 |
+
return round(sum(r[col] for r in bucket) / 60, 6)
|
| 352 |
+
|
| 353 |
+
def avg_v(col):
|
| 354 |
+
return round(sum(r[col] for r in bucket) / len(bucket), 2)
|
| 355 |
+
|
| 356 |
+
row = {"Time": first["Time"]}
|
| 357 |
+
|
| 358 |
+
if mode == "mean":
|
| 359 |
+
row["Solar_Flow_kW"] = mean("Solar_Flow_kW")
|
| 360 |
+
row["Shore_Flow_kW"] = mean("Shore_Flow_kW")
|
| 361 |
+
row["Battery_Flow_kW"] = mean("Battery_Flow_kW")
|
| 362 |
+
for c in CIRCUITS:
|
| 363 |
+
row[f"{c}_Flow_kW"] = mean(f"{c}_Flow_kW")
|
| 364 |
+
row["Battery_Level_Ah"] = last["Battery_Level_Ah"]
|
| 365 |
+
row["Battery_Level_Pct"] = last["Battery_Level_Pct"]
|
| 366 |
+
row["Solar_Voltage_V"] = avg_v("Solar_Voltage_V")
|
| 367 |
+
row["Battery_Voltage_V"] = avg_v("Battery_Voltage_V")
|
| 368 |
+
|
| 369 |
+
else:
|
| 370 |
+
row["Solar_Total_kWh"] = to_kwh("Solar_Flow_kW")
|
| 371 |
+
row["Shore_Total_kWh"] = to_kwh("Shore_Flow_kW")
|
| 372 |
+
# Battery split: charged (+) and discharged (-) as separate positive columns
|
| 373 |
+
row["Battery_Charged_kWh"] = round(
|
| 374 |
+
sum(r["Battery_Flow_kW"] for r in bucket if r["Battery_Flow_kW"] > 0) / 60, 6)
|
| 375 |
+
row["Battery_Discharged_kWh"] = round(
|
| 376 |
+
sum(abs(r["Battery_Flow_kW"]) for r in bucket if r["Battery_Flow_kW"] < 0) / 60, 6)
|
| 377 |
+
for c in CIRCUITS:
|
| 378 |
+
row[f"{c}_Total_kWh"] = to_kwh(f"{c}_Flow_kW")
|
| 379 |
+
row["Battery_Level_Ah"] = last["Battery_Level_Ah"]
|
| 380 |
+
row["Battery_Level_Pct"] = last["Battery_Level_Pct"]
|
| 381 |
+
row["Solar_Voltage_Avg_V"] = avg_v("Solar_Voltage_V")
|
| 382 |
+
row["Battery_Voltage_Avg_V"] = avg_v("Battery_Voltage_V")
|
| 383 |
+
|
| 384 |
+
out.append(row)
|
| 385 |
+
return out
|
| 386 |
+
|
| 387 |
+
|
| 388 |
+
def resample_water(rows: list[dict], interval_mins: int, mode: str = "mean",
|
| 389 |
+
fresh_cap_L: float = 378.5, grey_cap_L: float = 189.3,
|
| 390 |
+
black_cap_L: float = 170.3) -> list[dict]:
|
| 391 |
+
"""
|
| 392 |
+
mode='mean' β Lpm (15MIN flow file)
|
| 393 |
+
mode='sum' β L (1H, 1DAY energy files) [Lpm Γ 1 min = L]
|
| 394 |
+
|
| 395 |
+
Black tank level is a snapshot carried from 1MIN rows (derived from toilet flow).
|
| 396 |
+
"""
|
| 397 |
+
CIRCUITS = ["Inlet", "Pump", "Shower", "Kitchen", "Toilet", "Unmetered"]
|
| 398 |
+
out = []
|
| 399 |
+
|
| 400 |
+
for i in range(0, len(rows), interval_mins):
|
| 401 |
+
bucket = rows[i: i + interval_mins]
|
| 402 |
+
if not bucket:
|
| 403 |
+
continue
|
| 404 |
+
first, last = bucket[0], bucket[-1]
|
| 405 |
+
|
| 406 |
+
def mean_lpm(col):
|
| 407 |
+
return round(sum(r[col] for r in bucket) / len(bucket), 4)
|
| 408 |
+
|
| 409 |
+
def to_L(col):
|
| 410 |
+
return round(sum(r[col] for r in bucket), 4) # Lpm Γ 1 min = L
|
| 411 |
+
|
| 412 |
+
row = {"Time": first["Time"]}
|
| 413 |
+
|
| 414 |
+
if mode == "mean":
|
| 415 |
+
for c in CIRCUITS:
|
| 416 |
+
row[f"{c}_Flow_Lpm"] = mean_lpm(f"{c}_Flow_Lpm")
|
| 417 |
+
row["FreshTank_Level_L"] = last["FreshTank_Level_L"]
|
| 418 |
+
row["GreyTank_Level_L"] = last["GreyTank_Level_L"]
|
| 419 |
+
row["BlackTank_Level_L"] = last["BlackTank_Level_L"]
|
| 420 |
+
|
| 421 |
+
else:
|
| 422 |
+
for c in CIRCUITS:
|
| 423 |
+
row[f"{c}_Total_L"] = to_L(f"{c}_Flow_Lpm")
|
| 424 |
+
row["FreshTank_Level_L"] = last["FreshTank_Level_L"]
|
| 425 |
+
row["FreshTank_Level_Pct"] = round(last["FreshTank_Level_L"] / fresh_cap_L * 100, 2)
|
| 426 |
+
row["GreyTank_Level_L"] = last["GreyTank_Level_L"]
|
| 427 |
+
row["GreyTank_Level_Pct"] = round(last["GreyTank_Level_L"] / grey_cap_L * 100, 2)
|
| 428 |
+
row["BlackTank_Level_L"] = last["BlackTank_Level_L"]
|
| 429 |
+
row["BlackTank_Level_Pct"] = round(last["BlackTank_Level_L"] / black_cap_L * 100, 2)
|
| 430 |
+
|
| 431 |
+
out.append(row)
|
| 432 |
+
return out
|
| 433 |
+
|
| 434 |
+
|
| 435 |
+
# ---------------------------------------------------------------------------
|
| 436 |
+
# CSV WRITER
|
| 437 |
+
# ---------------------------------------------------------------------------
|
| 438 |
+
|
| 439 |
+
def write_csv(path: str, rows: list[dict]):
|
| 440 |
+
if not rows:
|
| 441 |
+
return
|
| 442 |
+
os.makedirs(os.path.dirname(path), exist_ok=True)
|
| 443 |
+
with open(path, "w", newline="") as f:
|
| 444 |
+
w = csv.DictWriter(f, fieldnames=rows[0].keys())
|
| 445 |
+
w.writeheader()
|
| 446 |
+
w.writerows(rows)
|
| 447 |
+
print(f" Wrote {len(rows):>6,} rows -> {path}")
|
| 448 |
+
|
| 449 |
+
|
| 450 |
+
# ---------------------------------------------------------------------------
|
| 451 |
+
# MAIN
|
| 452 |
+
# ---------------------------------------------------------------------------
|
| 453 |
+
|
| 454 |
+
def main():
|
| 455 |
+
parser = argparse.ArgumentParser(description="EV Camper Mock Data Generator")
|
| 456 |
+
parser.add_argument("--config", default="data.json", help="Path to data.json")
|
| 457 |
+
parser.add_argument("--out", default="output", help="Output directory")
|
| 458 |
+
parser.add_argument("--seed", type=int, default=42, help="Random seed")
|
| 459 |
+
parser.add_argument("--user", default=None, help="Glamper / Typical / Expert")
|
| 460 |
+
parser.add_argument("--people", type=int, default=None, help="Number of occupants")
|
| 461 |
+
parser.add_argument("--days", type=int, default=None, help="Trip duration in days")
|
| 462 |
+
parser.add_argument("--temp", default=None, help="Hot / Temperate / Cold")
|
| 463 |
+
parser.add_argument("--start", default="2026-02-18T00:00:00", help="Trip start (ISO datetime)")
|
| 464 |
+
args = parser.parse_args()
|
| 465 |
+
|
| 466 |
+
rng = random.Random(args.seed)
|
| 467 |
+
data = load_data(args.config)
|
| 468 |
+
|
| 469 |
+
params = data["inputs"]["params"]
|
| 470 |
+
specs = data["trailer_specs"]["specs"]
|
| 471 |
+
|
| 472 |
+
user = args.user or params["user_type"]["value"]
|
| 473 |
+
people = args.people or params["num_people"]["value"]
|
| 474 |
+
days = args.days or params["trip_duration_days"]["value"]
|
| 475 |
+
temp = args.temp or params["temperature"]["value"]
|
| 476 |
+
hvac_hrs = params["hvac_runtime_hrs"]["value"]
|
| 477 |
+
|
| 478 |
+
bat_cap_kwh = specs["battery_capacity_kwh"]["value"]
|
| 479 |
+
fresh_cap_gal = specs["freshwater_capacity_gal"]["value"]
|
| 480 |
+
grey_cap_gal = specs["greywater_capacity_gal"]["value"]
|
| 481 |
+
black_cap_gal = specs["blackwater_capacity_gal"]["value"]
|
| 482 |
+
fresh_cap_L = fresh_cap_gal * GAL_TO_LITRES
|
| 483 |
+
grey_cap_L = grey_cap_gal * GAL_TO_LITRES
|
| 484 |
+
black_cap_L = black_cap_gal * GAL_TO_LITRES
|
| 485 |
+
start = datetime.fromisoformat(args.start)
|
| 486 |
+
|
| 487 |
+
print(f"\n{'='*60}")
|
| 488 |
+
print(f" EV Camper Mock Data Generator")
|
| 489 |
+
print(f"{'='*60}")
|
| 490 |
+
print(f" Profile : {user} | People: {people} | Days: {days}")
|
| 491 |
+
print(f" Temp : {temp} | Start : {start.strftime('%Y-%m-%d')}")
|
| 492 |
+
print(f" Battery : {bat_cap_kwh} kWh | Fresh: {fresh_cap_gal} gal | Black: {black_cap_gal} gal")
|
| 493 |
+
print(f"{'='*60}\n")
|
| 494 |
+
|
| 495 |
+
pw = calc_power_budget(data, user, people, temp, hvac_hrs)
|
| 496 |
+
wat = calc_water_budget(data, user, people)
|
| 497 |
+
|
| 498 |
+
print(" Daily Power Budget:")
|
| 499 |
+
for k, v in pw.items(): print(f" {k:<22} {v:.3f} kWh")
|
| 500 |
+
print(f"\n Daily Water Budget:")
|
| 501 |
+
for k, v in wat.items(): print(f" {k:<22} {v:.1f} L")
|
| 502 |
+
print()
|
| 503 |
+
|
| 504 |
+
print(" Generating 1-minute base series...")
|
| 505 |
+
power_mins = build_power_minutes(pw, temp, bat_cap_kwh, start, days, rng)
|
| 506 |
+
water_mins = build_water_minutes(wat, fresh_cap_L, grey_cap_L, black_cap_L, start, days, rng)
|
| 507 |
+
|
| 508 |
+
out = Path(args.out)
|
| 509 |
+
|
| 510 |
+
# ------------------------------------------------------------------
|
| 511 |
+
# POWER FILES
|
| 512 |
+
# ------------------------------------------------------------------
|
| 513 |
+
pw_dir = out / "power"
|
| 514 |
+
print(" Resampling power files...")
|
| 515 |
+
|
| 516 |
+
# 1SEC: expand first 3h of 1-min rows to per-second with jitter
|
| 517 |
+
FLOW_COLS_KW = ["Solar_Flow_kW", "Shore_Flow_kW", "Battery_Flow_kW",
|
| 518 |
+
"HVAC_Flow_kW", "Lighting_Flow_kW", "Devices_Flow_kW",
|
| 519 |
+
"Fridge_Flow_kW", "WaterPump_Flow_kW", "Cooking_Flow_kW",
|
| 520 |
+
"Inverter_Flow_kW", "Unmetered_Flow_kW"]
|
| 521 |
+
sec_rows = []
|
| 522 |
+
for row in power_mins[:180]:
|
| 523 |
+
ts_base = datetime.strptime(row["Time"], "%Y-%m-%dT%H:%M:%SZ")
|
| 524 |
+
for s in range(60):
|
| 525 |
+
sr = dict(row)
|
| 526 |
+
sr["Time"] = (ts_base + timedelta(seconds=s)).strftime("%Y-%m-%dT%H:%M:%SZ")
|
| 527 |
+
for col in FLOW_COLS_KW:
|
| 528 |
+
sr[col] = round(max(0, row[col] * jitter(rng, 0.03)), 4)
|
| 529 |
+
sec_rows.append(sr)
|
| 530 |
+
|
| 531 |
+
write_csv(str(pw_dir / "1SEC.csv"), sec_rows)
|
| 532 |
+
write_csv(str(pw_dir / "1MIN.csv"), power_mins)
|
| 533 |
+
write_csv(str(pw_dir / "15MIN.csv"), resample_power(power_mins, 15, "mean"))
|
| 534 |
+
write_csv(str(pw_dir / "1H.csv"), resample_power(power_mins, 60, "sum"))
|
| 535 |
+
write_csv(str(pw_dir / "1DAY.csv"), resample_power(power_mins, MINS_PER_DAY,"sum"))
|
| 536 |
+
|
| 537 |
+
# ------------------------------------------------------------------
|
| 538 |
+
# WATER FILES
|
| 539 |
+
# ------------------------------------------------------------------
|
| 540 |
+
wt_dir = out / "water"
|
| 541 |
+
print(" Resampling water files...")
|
| 542 |
+
|
| 543 |
+
write_csv(str(wt_dir / "1MIN.csv"), water_mins)
|
| 544 |
+
write_csv(str(wt_dir / "15MIN.csv"), resample_water(water_mins, 15, "mean", fresh_cap_L, grey_cap_L, black_cap_L))
|
| 545 |
+
write_csv(str(wt_dir / "1H.csv"), resample_water(water_mins, 60, "sum", fresh_cap_L, grey_cap_L, black_cap_L))
|
| 546 |
+
write_csv(str(wt_dir / "1DAY.csv"), resample_water(water_mins, MINS_PER_DAY, "sum", fresh_cap_L, grey_cap_L, black_cap_L))
|
| 547 |
+
|
| 548 |
+
|
| 549 |
+
if __name__ == "__main__":
|
| 550 |
+
main()
|
main.py
CHANGED
|
@@ -1,64 +1,418 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
import
|
| 6 |
-
import
|
| 7 |
-
from
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
EV Camper Dashboard - FastAPI Backend
|
| 3 |
+
"""
|
| 4 |
+
import csv
|
| 5 |
+
import json
|
| 6 |
+
import os
|
| 7 |
+
from pathlib import Path
|
| 8 |
+
from typing import Optional
|
| 9 |
+
from fastapi import FastAPI, Query
|
| 10 |
+
from fastapi.middleware.cors import CORSMiddleware
|
| 11 |
+
from fastapi.staticfiles import StaticFiles
|
| 12 |
+
from fastapi.responses import FileResponse, JSONResponse
|
| 13 |
+
|
| 14 |
+
app = FastAPI(title="EV Camper Dashboard API", version="1.0")
|
| 15 |
+
|
| 16 |
+
app.add_middleware(
|
| 17 |
+
CORSMiddleware,
|
| 18 |
+
allow_origins=["*"],
|
| 19 |
+
allow_methods=["*"],
|
| 20 |
+
allow_headers=["*"],
|
| 21 |
+
)
|
| 22 |
+
|
| 23 |
+
DATA_DIR = Path("output")
|
| 24 |
+
CONFIG_PATH = Path("data.json")
|
| 25 |
+
|
| 26 |
+
# ββ Helpers ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 27 |
+
|
| 28 |
+
def read_csv(path: Path, limit: int = None, offset: int = 0) -> list[dict]:
|
| 29 |
+
if not path.exists():
|
| 30 |
+
return []
|
| 31 |
+
with open(path) as f:
|
| 32 |
+
reader = csv.DictReader(f)
|
| 33 |
+
rows = []
|
| 34 |
+
for i, row in enumerate(reader):
|
| 35 |
+
if i < offset:
|
| 36 |
+
continue
|
| 37 |
+
parsed = {}
|
| 38 |
+
for k, v in row.items():
|
| 39 |
+
if k == "Time":
|
| 40 |
+
parsed[k] = v
|
| 41 |
+
continue
|
| 42 |
+
try:
|
| 43 |
+
parsed[k] = float(v)
|
| 44 |
+
except (ValueError, TypeError):
|
| 45 |
+
parsed[k] = v
|
| 46 |
+
rows.append(parsed)
|
| 47 |
+
if limit and len(rows) >= limit:
|
| 48 |
+
break
|
| 49 |
+
return rows
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
def load_config() -> dict:
|
| 53 |
+
with open(CONFIG_PATH) as f:
|
| 54 |
+
return json.load(f)
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
# ββ Config & Specs βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 58 |
+
|
| 59 |
+
@app.get("/api/config")
|
| 60 |
+
def get_config():
|
| 61 |
+
"""Return trip configuration and trailer specs."""
|
| 62 |
+
cfg = load_config()
|
| 63 |
+
return {
|
| 64 |
+
"inputs": cfg["inputs"],
|
| 65 |
+
"trailer_specs": cfg["trailer_specs"],
|
| 66 |
+
}
|
| 67 |
+
|
| 68 |
+
|
| 69 |
+
@app.get("/api/components")
|
| 70 |
+
def get_components():
|
| 71 |
+
"""Return all trailer components by category."""
|
| 72 |
+
cfg = load_config()
|
| 73 |
+
comps = cfg["lookups"]["components"]
|
| 74 |
+
schema = comps["schema"]
|
| 75 |
+
result = {}
|
| 76 |
+
for category in ["living", "cooking", "toilet", "shower", "laundry", "actuation", "dumping", "hvac"]:
|
| 77 |
+
if category in comps:
|
| 78 |
+
result[category] = [
|
| 79 |
+
dict(zip(schema, item)) for item in comps[category]
|
| 80 |
+
]
|
| 81 |
+
return result
|
| 82 |
+
|
| 83 |
+
|
| 84 |
+
# ββ Budget Endpoints βββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 85 |
+
|
| 86 |
+
@app.get("/api/power/budget")
|
| 87 |
+
def get_power_budget():
|
| 88 |
+
"""Daily power budget breakdown in kWh."""
|
| 89 |
+
cfg = load_config()
|
| 90 |
+
from generate_mock_data import calc_power_budget
|
| 91 |
+
params = cfg["inputs"]["params"]
|
| 92 |
+
return calc_power_budget(
|
| 93 |
+
cfg,
|
| 94 |
+
params["user_type"]["value"],
|
| 95 |
+
params["num_people"]["value"],
|
| 96 |
+
params["temperature"]["value"],
|
| 97 |
+
params["hvac_runtime_hrs"]["value"],
|
| 98 |
+
)
|
| 99 |
+
|
| 100 |
+
|
| 101 |
+
@app.get("/api/water/budget")
|
| 102 |
+
def get_water_budget():
|
| 103 |
+
"""Daily water budget breakdown in litres."""
|
| 104 |
+
cfg = load_config()
|
| 105 |
+
from generate_mock_data import calc_water_budget
|
| 106 |
+
params = cfg["inputs"]["params"]
|
| 107 |
+
return calc_water_budget(
|
| 108 |
+
cfg,
|
| 109 |
+
params["user_type"]["value"],
|
| 110 |
+
params["num_people"]["value"],
|
| 111 |
+
)
|
| 112 |
+
|
| 113 |
+
|
| 114 |
+
# ββ Time Series Endpoints ββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 115 |
+
|
| 116 |
+
POWER_RESOLUTIONS = {"1SEC", "1MIN", "15MIN", "1H", "1DAY"}
|
| 117 |
+
WATER_RESOLUTIONS = {"1MIN", "15MIN", "1H", "1DAY"}
|
| 118 |
+
|
| 119 |
+
|
| 120 |
+
# ββ Hourly Profile (MUST be before /{resolution} routes) ββββββββββββββββ
|
| 121 |
+
|
| 122 |
+
@app.get("/api/power/hourly-profile")
|
| 123 |
+
def get_hourly_profile():
|
| 124 |
+
"""Average hourly power profile across all trip days."""
|
| 125 |
+
hourly = read_csv(DATA_DIR / "power" / "1H.csv")
|
| 126 |
+
circuits = ["HVAC", "Lighting", "Devices", "Fridge", "WaterPump", "Cooking", "Inverter"]
|
| 127 |
+
|
| 128 |
+
from collections import defaultdict
|
| 129 |
+
from datetime import datetime as dt
|
| 130 |
+
hour_buckets = defaultdict(lambda: defaultdict(list))
|
| 131 |
+
|
| 132 |
+
for row in hourly:
|
| 133 |
+
ts = dt.fromisoformat(row["Time"].replace("Z", ""))
|
| 134 |
+
h = ts.hour
|
| 135 |
+
hour_buckets[h]["solar"].append(row.get("Solar_Total_kWh", 0))
|
| 136 |
+
for c in circuits:
|
| 137 |
+
hour_buckets[h][c].append(row.get(f"{c}_Total_kWh", 0))
|
| 138 |
+
hour_buckets[h]["battery_pct"].append(row.get("Battery_Level_Pct", 0))
|
| 139 |
+
|
| 140 |
+
profile = []
|
| 141 |
+
for h in range(24):
|
| 142 |
+
entry = {"hour": h}
|
| 143 |
+
if h in hour_buckets:
|
| 144 |
+
b = hour_buckets[h]
|
| 145 |
+
entry["solar_kwh"] = round(sum(b["solar"]) / len(b["solar"]), 4)
|
| 146 |
+
entry["battery_pct"] = round(sum(b["battery_pct"]) / len(b["battery_pct"]), 1)
|
| 147 |
+
for c in circuits:
|
| 148 |
+
entry[f"{c}_kwh"] = round(sum(b[c]) / len(b[c]), 4)
|
| 149 |
+
entry["total_load_kwh"] = round(sum(entry.get(f"{c}_kwh", 0) for c in circuits), 4)
|
| 150 |
+
profile.append(entry)
|
| 151 |
+
return profile
|
| 152 |
+
|
| 153 |
+
|
| 154 |
+
@app.get("/api/water/hourly-profile")
|
| 155 |
+
def get_water_hourly_profile():
|
| 156 |
+
"""Average hourly water usage profile."""
|
| 157 |
+
hourly = read_csv(DATA_DIR / "water" / "1H.csv")
|
| 158 |
+
circuits = ["Shower", "Kitchen", "Toilet"]
|
| 159 |
+
|
| 160 |
+
from collections import defaultdict
|
| 161 |
+
from datetime import datetime as dt
|
| 162 |
+
hour_buckets = defaultdict(lambda: defaultdict(list))
|
| 163 |
+
|
| 164 |
+
for row in hourly:
|
| 165 |
+
ts = dt.fromisoformat(row["Time"].replace("Z", ""))
|
| 166 |
+
h = ts.hour
|
| 167 |
+
for c in circuits:
|
| 168 |
+
hour_buckets[h][c].append(row.get(f"{c}_Total_L", 0))
|
| 169 |
+
hour_buckets[h]["fresh_pct"].append(
|
| 170 |
+
row.get("FreshTank_Level_Pct", row.get("FreshTank_Level_L", 0) / 378.5 * 100)
|
| 171 |
+
)
|
| 172 |
+
|
| 173 |
+
profile = []
|
| 174 |
+
for h in range(24):
|
| 175 |
+
entry = {"hour": h}
|
| 176 |
+
if h in hour_buckets:
|
| 177 |
+
b = hour_buckets[h]
|
| 178 |
+
for c in circuits:
|
| 179 |
+
entry[f"{c}_L"] = round(sum(b[c]) / len(b[c]), 3)
|
| 180 |
+
entry["total_L"] = round(sum(entry.get(f"{c}_L", 0) for c in circuits), 3)
|
| 181 |
+
entry["fresh_pct"] = round(sum(b["fresh_pct"]) / len(b["fresh_pct"]), 1)
|
| 182 |
+
profile.append(entry)
|
| 183 |
+
return profile
|
| 184 |
+
|
| 185 |
+
|
| 186 |
+
@app.get("/api/power/peaks")
|
| 187 |
+
def get_power_peaks():
|
| 188 |
+
"""Identify peak power usage hours across the trip."""
|
| 189 |
+
hourly = read_csv(DATA_DIR / "power" / "1H.csv")
|
| 190 |
+
circuits = ["HVAC", "Lighting", "Devices", "Fridge", "WaterPump", "Cooking", "Inverter"]
|
| 191 |
+
|
| 192 |
+
peaks = []
|
| 193 |
+
for row in hourly:
|
| 194 |
+
total = sum(row.get(f"{c}_Total_kWh", 0) for c in circuits)
|
| 195 |
+
peaks.append({
|
| 196 |
+
"time": row["Time"],
|
| 197 |
+
"total_kwh": round(total, 4),
|
| 198 |
+
"solar_kwh": row.get("Solar_Total_kWh", 0),
|
| 199 |
+
"battery_pct": row.get("Battery_Level_Pct", 0),
|
| 200 |
+
})
|
| 201 |
+
|
| 202 |
+
peaks.sort(key=lambda x: x["total_kwh"], reverse=True)
|
| 203 |
+
return {
|
| 204 |
+
"top_10_peak_hours": peaks[:10],
|
| 205 |
+
"bottom_10_hours": sorted(peaks, key=lambda x: x["total_kwh"])[:10],
|
| 206 |
+
}
|
| 207 |
+
|
| 208 |
+
|
| 209 |
+
@app.get("/api/power/{resolution}")
|
| 210 |
+
def get_power_data(
|
| 211 |
+
resolution: str,
|
| 212 |
+
limit: Optional[int] = Query(None, ge=1, le=50000),
|
| 213 |
+
offset: int = Query(0, ge=0),
|
| 214 |
+
day: Optional[int] = Query(None, ge=1, le=30, description="Filter by day number"),
|
| 215 |
+
):
|
| 216 |
+
"""Power time-series data at given resolution."""
|
| 217 |
+
res = resolution.upper()
|
| 218 |
+
if res not in POWER_RESOLUTIONS:
|
| 219 |
+
return JSONResponse({"error": f"Invalid resolution. Use: {POWER_RESOLUTIONS}"}, 400)
|
| 220 |
+
|
| 221 |
+
path = DATA_DIR / "power" / f"{res}.csv"
|
| 222 |
+
|
| 223 |
+
# When day filter is active, read all rows first, then filter
|
| 224 |
+
if day is not None:
|
| 225 |
+
rows = read_csv(path)
|
| 226 |
+
if rows:
|
| 227 |
+
from datetime import datetime
|
| 228 |
+
start_date = datetime.fromisoformat(rows[0]["Time"].replace("Z", "")).date()
|
| 229 |
+
rows = [r for r in rows
|
| 230 |
+
if (datetime.fromisoformat(r["Time"].replace("Z", "")).date() - start_date).days + 1 == day]
|
| 231 |
+
if limit:
|
| 232 |
+
rows = rows[offset:offset + limit]
|
| 233 |
+
else:
|
| 234 |
+
rows = read_csv(path, limit=limit, offset=offset)
|
| 235 |
+
|
| 236 |
+
return {"resolution": res, "count": len(rows), "data": rows}
|
| 237 |
+
|
| 238 |
+
|
| 239 |
+
@app.get("/api/water/{resolution}")
|
| 240 |
+
def get_water_data(
|
| 241 |
+
resolution: str,
|
| 242 |
+
limit: Optional[int] = Query(None, ge=1, le=50000),
|
| 243 |
+
offset: int = Query(0, ge=0),
|
| 244 |
+
day: Optional[int] = Query(None, ge=1, le=30),
|
| 245 |
+
):
|
| 246 |
+
"""Water time-series data at given resolution."""
|
| 247 |
+
res = resolution.upper()
|
| 248 |
+
if res not in WATER_RESOLUTIONS:
|
| 249 |
+
return JSONResponse({"error": f"Invalid resolution. Use: {WATER_RESOLUTIONS}"}, 400)
|
| 250 |
+
|
| 251 |
+
path = DATA_DIR / "water" / f"{res}.csv"
|
| 252 |
+
|
| 253 |
+
if day is not None:
|
| 254 |
+
rows = read_csv(path)
|
| 255 |
+
if rows:
|
| 256 |
+
from datetime import datetime
|
| 257 |
+
start_date = datetime.fromisoformat(rows[0]["Time"].replace("Z", "")).date()
|
| 258 |
+
rows = [r for r in rows
|
| 259 |
+
if (datetime.fromisoformat(r["Time"].replace("Z", "")).date() - start_date).days + 1 == day]
|
| 260 |
+
if limit:
|
| 261 |
+
rows = rows[offset:offset + limit]
|
| 262 |
+
else:
|
| 263 |
+
rows = read_csv(path, limit=limit, offset=offset)
|
| 264 |
+
|
| 265 |
+
return {"resolution": res, "count": len(rows), "data": rows}
|
| 266 |
+
|
| 267 |
+
|
| 268 |
+
# ββ Summary / Aggregated Stats βββββββββββββββββββββββββββββββββββββββββββ
|
| 269 |
+
|
| 270 |
+
@app.get("/api/summary")
|
| 271 |
+
def get_summary():
|
| 272 |
+
"""Trip-wide summary statistics."""
|
| 273 |
+
daily_power = read_csv(DATA_DIR / "power" / "1DAY.csv")
|
| 274 |
+
daily_water = read_csv(DATA_DIR / "water" / "1DAY.csv")
|
| 275 |
+
hourly_power = read_csv(DATA_DIR / "power" / "1H.csv")
|
| 276 |
+
|
| 277 |
+
if not daily_power:
|
| 278 |
+
return {"error": "No data"}
|
| 279 |
+
|
| 280 |
+
circuits = ["HVAC", "Lighting", "Devices", "Fridge", "WaterPump", "Cooking", "Inverter", "Unmetered"]
|
| 281 |
+
|
| 282 |
+
total_solar = sum(d.get("Solar_Total_kWh", 0) for d in daily_power)
|
| 283 |
+
total_shore = sum(d.get("Shore_Total_kWh", 0) for d in daily_power)
|
| 284 |
+
total_consumption = sum(
|
| 285 |
+
sum(d.get(f"{c}_Total_kWh", 0) for c in circuits)
|
| 286 |
+
for d in daily_power
|
| 287 |
+
)
|
| 288 |
+
|
| 289 |
+
# Per-circuit totals
|
| 290 |
+
circuit_totals = {}
|
| 291 |
+
for c in circuits:
|
| 292 |
+
circuit_totals[c] = round(sum(d.get(f"{c}_Total_kWh", 0) for d in daily_power), 3)
|
| 293 |
+
|
| 294 |
+
# Battery stats
|
| 295 |
+
min_battery = min(d.get("Battery_Level_Pct", 100) for d in hourly_power) if hourly_power else 0
|
| 296 |
+
max_battery = max(d.get("Battery_Level_Pct", 0) for d in hourly_power) if hourly_power else 100
|
| 297 |
+
avg_battery = sum(d.get("Battery_Level_Pct", 0) for d in hourly_power) / len(hourly_power) if hourly_power else 0
|
| 298 |
+
|
| 299 |
+
# Water totals
|
| 300 |
+
total_fresh_used = 0
|
| 301 |
+
if daily_water:
|
| 302 |
+
total_fresh_used = sum(d.get("Pump_Total_L", 0) for d in daily_water)
|
| 303 |
+
|
| 304 |
+
# Final tank levels
|
| 305 |
+
last_water = daily_water[-1] if daily_water else {}
|
| 306 |
+
last_power = hourly_power[-1] if hourly_power else {}
|
| 307 |
+
|
| 308 |
+
# Daily breakdown
|
| 309 |
+
daily_breakdown = []
|
| 310 |
+
for i, dp in enumerate(daily_power):
|
| 311 |
+
dw = daily_water[i] if i < len(daily_water) else {}
|
| 312 |
+
daily_breakdown.append({
|
| 313 |
+
"day": i + 1,
|
| 314 |
+
"solar_kwh": round(dp.get("Solar_Total_kWh", 0), 2),
|
| 315 |
+
"consumption_kwh": round(sum(dp.get(f"{c}_Total_kWh", 0) for c in circuits), 2),
|
| 316 |
+
"shore_kwh": round(dp.get("Shore_Total_kWh", 0), 2),
|
| 317 |
+
"battery_end_pct": dp.get("Battery_Level_Pct", 0),
|
| 318 |
+
"fresh_used_L": round(dw.get("Pump_Total_L", 0), 1),
|
| 319 |
+
"fresh_remaining_pct": round(dw.get("FreshTank_Level_Pct", 0), 1),
|
| 320 |
+
})
|
| 321 |
+
|
| 322 |
+
return {
|
| 323 |
+
"trip_days": len(daily_power),
|
| 324 |
+
"total_solar_kwh": round(total_solar, 2),
|
| 325 |
+
"total_shore_kwh": round(total_shore, 2),
|
| 326 |
+
"total_consumption_kwh": round(total_consumption, 2),
|
| 327 |
+
"self_sufficiency_pct": round(total_solar / max(total_consumption, 0.01) * 100, 1),
|
| 328 |
+
"circuit_totals_kwh": circuit_totals,
|
| 329 |
+
"battery": {
|
| 330 |
+
"min_pct": round(min_battery, 1),
|
| 331 |
+
"max_pct": round(max_battery, 1),
|
| 332 |
+
"avg_pct": round(avg_battery, 1),
|
| 333 |
+
"current_pct": last_power.get("Battery_Level_Pct", 0),
|
| 334 |
+
},
|
| 335 |
+
"water": {
|
| 336 |
+
"total_fresh_used_L": round(total_fresh_used, 1),
|
| 337 |
+
"fresh_remaining_L": last_water.get("FreshTank_Level_L", 0),
|
| 338 |
+
"fresh_remaining_pct": last_water.get("FreshTank_Level_Pct", 0),
|
| 339 |
+
"grey_level_L": last_water.get("GreyTank_Level_L", 0),
|
| 340 |
+
"grey_level_pct": last_water.get("GreyTank_Level_Pct", 0),
|
| 341 |
+
"black_level_L": last_water.get("BlackTank_Level_L", 0),
|
| 342 |
+
"black_level_pct": last_water.get("BlackTank_Level_Pct", 0),
|
| 343 |
+
},
|
| 344 |
+
"daily_breakdown": daily_breakdown,
|
| 345 |
+
}
|
| 346 |
+
|
| 347 |
+
|
| 348 |
+
# ββ Serve Frontend βββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 349 |
+
|
| 350 |
+
# ββ Data Regeneration ββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 351 |
+
|
| 352 |
+
from pydantic import BaseModel
|
| 353 |
+
|
| 354 |
+
class GenerateRequest(BaseModel):
|
| 355 |
+
user_type: str = "Typical"
|
| 356 |
+
num_people: int = 2
|
| 357 |
+
trip_duration_days: int = 5
|
| 358 |
+
temperature: str = "Hot"
|
| 359 |
+
sunlight: str = "Hi- Sunny"
|
| 360 |
+
humidity: str = "Comfortable"
|
| 361 |
+
seed: int = 42
|
| 362 |
+
|
| 363 |
+
@app.post("/api/generate")
|
| 364 |
+
def regenerate_data(req: GenerateRequest):
|
| 365 |
+
"""Regenerate mock data with new parameters."""
|
| 366 |
+
import subprocess, sys
|
| 367 |
+
|
| 368 |
+
# Update config in memory for budget endpoints
|
| 369 |
+
cfg = load_config()
|
| 370 |
+
cfg["inputs"]["params"]["user_type"]["value"] = req.user_type
|
| 371 |
+
cfg["inputs"]["params"]["num_people"]["value"] = req.num_people
|
| 372 |
+
cfg["inputs"]["params"]["trip_duration_days"]["value"] = req.trip_duration_days
|
| 373 |
+
cfg["inputs"]["params"]["temperature"]["value"] = req.temperature
|
| 374 |
+
cfg["inputs"]["params"]["sunlight"]["value"] = req.sunlight
|
| 375 |
+
cfg["inputs"]["params"]["humidity"]["value"] = req.humidity
|
| 376 |
+
|
| 377 |
+
# Write updated config
|
| 378 |
+
with open(CONFIG_PATH, "w") as f:
|
| 379 |
+
json.dump(cfg, f, indent=2)
|
| 380 |
+
|
| 381 |
+
# Run the generator
|
| 382 |
+
result = subprocess.run(
|
| 383 |
+
[sys.executable, "generate_mock_data.py",
|
| 384 |
+
"--config", str(CONFIG_PATH),
|
| 385 |
+
"--out", str(DATA_DIR),
|
| 386 |
+
"--seed", str(req.seed),
|
| 387 |
+
"--user", req.user_type,
|
| 388 |
+
"--people", str(req.num_people),
|
| 389 |
+
"--days", str(req.trip_duration_days),
|
| 390 |
+
"--temp", req.temperature],
|
| 391 |
+
capture_output=True, text=True, timeout=120,
|
| 392 |
+
)
|
| 393 |
+
|
| 394 |
+
if result.returncode != 0:
|
| 395 |
+
return JSONResponse({"error": result.stderr}, 500)
|
| 396 |
+
|
| 397 |
+
return {"status": "ok", "message": f"Generated {req.trip_duration_days}-day trip for {req.user_type} profile"}
|
| 398 |
+
|
| 399 |
+
|
| 400 |
+
# ββ Serve Frontend (catch-all, must be LAST) βββββββββββββββββββββββββββββ
|
| 401 |
+
|
| 402 |
+
STATIC_DIR = Path("static")
|
| 403 |
+
|
| 404 |
+
@app.get("/")
|
| 405 |
+
def serve_index():
|
| 406 |
+
return FileResponse(STATIC_DIR / "index.html")
|
| 407 |
+
|
| 408 |
+
@app.get("/{path:path}")
|
| 409 |
+
def serve_static(path: str):
|
| 410 |
+
file_path = STATIC_DIR / path
|
| 411 |
+
if file_path.exists() and file_path.is_file():
|
| 412 |
+
return FileResponse(file_path)
|
| 413 |
+
return FileResponse(STATIC_DIR / "index.html")
|
| 414 |
+
|
| 415 |
+
|
| 416 |
+
if __name__ == "__main__":
|
| 417 |
+
import uvicorn
|
| 418 |
+
uvicorn.run(app, host="0.0.0.0", port=8000)
|
output/power/15MIN.csv
ADDED
|
@@ -0,0 +1,385 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Time,Solar_Flow_kW,Shore_Flow_kW,Battery_Flow_kW,HVAC_Flow_kW,Lighting_Flow_kW,Devices_Flow_kW,Fridge_Flow_kW,WaterPump_Flow_kW,Cooking_Flow_kW,Inverter_Flow_kW,Unmetered_Flow_kW,Battery_Level_Ah,Battery_Level_Pct,Solar_Voltage_V,Battery_Voltage_V
|
| 2 |
+
2026-02-18T00:00:00Z,0.0,0.0,-0.8439,0.6457,0.002,0.1361,0.0593,0.0,0.0,0.0008,0.0,1662.3,79.79,0.0,50.75
|
| 3 |
+
2026-02-18T00:15:00Z,0.0,0.0,-0.8473,0.6497,0.002,0.1344,0.0604,0.0,0.0,0.0009,0.0,1657.9,79.58,0.0,50.82
|
| 4 |
+
2026-02-18T00:30:00Z,0.0,0.0,-0.886,0.6815,0.002,0.1349,0.0667,0.0,0.0,0.0009,0.0,1653.2,79.36,0.0,50.79
|
| 5 |
+
2026-02-18T00:45:00Z,0.0,0.0,-0.8442,0.6411,0.002,0.1374,0.0629,0.0,0.0,0.0008,0.0,1648.8,79.14,0.0,50.82
|
| 6 |
+
2026-02-18T01:00:00Z,0.0,0.0,-0.8365,0.6364,0.002,0.1341,0.0632,0.0,0.0,0.0009,0.0,1644.5,78.94,0.0,50.78
|
| 7 |
+
2026-02-18T01:15:00Z,0.0,0.0,-0.8253,0.6328,0.002,0.1355,0.0542,0.0,0.0,0.0008,0.0,1640.2,78.73,0.0,50.68
|
| 8 |
+
2026-02-18T01:30:00Z,0.0,0.0,-0.8569,0.6603,0.002,0.1331,0.0606,0.0,0.0,0.0008,0.0,1635.7,78.51,0.0,50.71
|
| 9 |
+
2026-02-18T01:45:00Z,0.0,0.0,-0.8666,0.666,0.002,0.1331,0.0647,0.0,0.0,0.0008,0.0,1631.2,78.3,0.0,50.61
|
| 10 |
+
2026-02-18T02:00:00Z,0.0,0.0,-0.8384,0.6349,0.002,0.135,0.0657,0.0,0.0,0.0009,0.0,1626.8,78.09,0.0,50.72
|
| 11 |
+
2026-02-18T02:15:00Z,0.0,0.0,-0.872,0.6702,0.002,0.1376,0.0614,0.0,0.0,0.0009,0.0,1622.3,77.87,0.0,50.7
|
| 12 |
+
2026-02-18T02:30:00Z,0.0,0.0,-0.826,0.63,0.002,0.135,0.0581,0.0,0.0,0.0009,0.0,1618.0,77.66,0.0,50.65
|
| 13 |
+
2026-02-18T02:45:00Z,0.0,0.0,-0.8538,0.6556,0.002,0.1358,0.0596,0.0,0.0,0.0008,0.0,1613.6,77.45,0.0,50.61
|
| 14 |
+
2026-02-18T03:00:00Z,0.0,0.0,-0.8751,0.6698,0.002,0.1358,0.0667,0.0,0.0,0.0008,0.0,1609.0,77.23,0.0,50.65
|
| 15 |
+
2026-02-18T03:15:00Z,0.0,0.0,-0.8784,0.6805,0.002,0.1349,0.0603,0.0,0.0,0.0008,0.0,1604.4,77.01,0.0,50.69
|
| 16 |
+
2026-02-18T03:30:00Z,0.0,0.0,-0.8682,0.6666,0.002,0.1363,0.0625,0.0,0.0,0.0008,0.0,1599.9,76.8,0.0,50.64
|
| 17 |
+
2026-02-18T03:45:00Z,0.0,0.0,-0.8562,0.6563,0.002,0.136,0.0609,0.0,0.0,0.0008,0.0,1595.4,76.58,0.0,50.61
|
| 18 |
+
2026-02-18T04:00:00Z,0.0,0.0,-0.848,0.6503,0.002,0.1343,0.0604,0.0001,0.0,0.0008,0.0,1591.0,76.37,0.0,50.56
|
| 19 |
+
2026-02-18T04:15:00Z,0.0,0.0,-0.8574,0.6537,0.002,0.1347,0.0658,0.0003,0.0,0.0009,0.0,1586.6,76.15,0.0,50.69
|
| 20 |
+
2026-02-18T04:30:00Z,0.0,0.0,-0.8579,0.6544,0.002,0.1351,0.0642,0.0006,0.0,0.0016,0.0,1582.1,75.94,0.0,50.68
|
| 21 |
+
2026-02-18T04:45:00Z,0.0,0.0,-0.8443,0.6425,0.002,0.1359,0.06,0.0011,0.0,0.0028,0.0,1577.7,75.73,0.0,50.54
|
| 22 |
+
2026-02-18T05:00:00Z,0.0,0.0,-0.8285,0.6211,0.002,0.1353,0.0635,0.002,0.0,0.0047,0.0,1573.4,75.52,0.0,50.49
|
| 23 |
+
2026-02-18T05:15:00Z,0.0,0.0,-0.8561,0.6441,0.002,0.1342,0.0648,0.0034,0.0,0.0076,0.0,1568.9,75.31,0.0,50.54
|
| 24 |
+
2026-02-18T05:30:00Z,0.0,0.0,-0.8796,0.6649,0.002,0.1352,0.0604,0.0058,0.0,0.0113,0.0,1564.3,75.09,0.0,50.54
|
| 25 |
+
2026-02-18T05:45:00Z,0.0,0.0,-0.8912,0.6674,0.002,0.1351,0.0603,0.009,0.0,0.0175,0.0,1559.7,74.87,0.0,50.55
|
| 26 |
+
2026-02-18T06:00:00Z,0.1547,0.0,-1.4081,0.6182,0.0652,0.138,0.0596,0.0137,0.6419,0.0262,0.0,1552.4,74.51,39.89,50.44
|
| 27 |
+
2026-02-18T06:15:00Z,0.4883,0.0,-2.3503,0.6452,0.0852,0.135,0.0619,0.0162,1.8616,0.0334,0.0,1540.1,73.93,45.75,50.39
|
| 28 |
+
2026-02-18T06:30:00Z,0.8025,0.0,-2.3551,0.6183,0.1103,0.1337,0.0612,0.0213,2.1688,0.0441,0.0,1527.9,73.34,43.41,50.44
|
| 29 |
+
2026-02-18T06:45:00Z,1.1306,0.0,-2.8756,0.6027,0.1384,0.1374,0.0592,0.0264,2.9856,0.0564,0.0,1512.9,72.62,43.48,50.39
|
| 30 |
+
2026-02-18T07:00:00Z,1.476,0.0,-3.2121,0.6039,0.1614,0.1363,0.0624,0.0319,3.6273,0.0649,0.0,1496.2,71.82,45.84,50.36
|
| 31 |
+
2026-02-18T07:15:00Z,1.7733,0.0,-3.3301,0.5751,0.185,0.1338,0.0649,0.0325,4.039,0.0732,0.0,1478.8,70.98,46.25,50.28
|
| 32 |
+
2026-02-18T07:30:00Z,2.0023,0.0,-3.6063,0.5594,0.2082,0.1349,0.0649,0.0326,4.5303,0.0784,0.0,1460.0,70.08,43.81,50.25
|
| 33 |
+
2026-02-18T07:45:00Z,2.4342,0.0,-3.2063,0.5409,0.2123,0.1355,0.0592,0.03,4.5796,0.0831,0.0,1443.3,69.28,43.97,50.17
|
| 34 |
+
2026-02-18T08:00:00Z,2.7277,0.0,-3.0941,0.562,0.2173,0.1379,0.0591,0.0271,4.7354,0.0829,0.0,1427.2,68.51,43.35,50.06
|
| 35 |
+
2026-02-18T08:15:00Z,2.8681,0.0,-2.4137,0.5295,0.2055,0.1355,0.0572,0.0229,4.2538,0.0773,0.0,1414.6,67.9,43.83,50.15
|
| 36 |
+
2026-02-18T08:30:00Z,3.0694,0.0,-2.0128,0.5341,0.19,0.1359,0.0592,0.0174,4.0722,0.0735,0.0,1404.2,67.4,43.27,50.1
|
| 37 |
+
2026-02-18T08:45:00Z,3.3925,0.0,-1.306,0.5199,0.1694,0.1331,0.0654,0.0127,3.7326,0.0654,0.0,1397.4,67.07,46.74,50.08
|
| 38 |
+
2026-02-18T09:00:00Z,3.5239,0.0,-0.1379,0.5072,0.1369,0.1335,0.0597,0.0093,2.7617,0.0537,0.0,1396.6,67.04,45.58,50.03
|
| 39 |
+
2026-02-18T09:15:00Z,3.8021,0.0,0.5365,0.4732,0.1112,0.1346,0.0629,0.0058,2.4329,0.045,0.0,1399.4,67.17,43.25,50.01
|
| 40 |
+
2026-02-18T09:30:00Z,4.0544,0.0,1.5088,0.492,0.0874,0.1349,0.0563,0.0034,1.7376,0.0338,0.0,1407.3,67.55,44.67,50.08
|
| 41 |
+
2026-02-18T09:45:00Z,4.1875,0.0,2.7069,0.4918,0.0646,0.1347,0.0627,0.002,0.7005,0.0243,0.0,1421.4,68.23,44.43,50.11
|
| 42 |
+
2026-02-18T10:00:00Z,4.394,0.0,3.6574,0.4761,0.0457,0.134,0.0628,0.0011,0.0,0.0171,0.0,1440.4,69.14,44.67,50.08
|
| 43 |
+
2026-02-18T10:15:00Z,4.5218,0.0,3.8006,0.482,0.0313,0.1346,0.061,0.0005,0.0,0.0119,0.0,1460.2,70.09,43.98,50.11
|
| 44 |
+
2026-02-18T10:30:00Z,4.6468,0.0,3.9491,0.473,0.02,0.1352,0.061,0.0003,0.0,0.0082,0.0,1480.8,71.08,44.07,50.35
|
| 45 |
+
2026-02-18T10:45:00Z,4.7168,0.0,4.0487,0.458,0.0122,0.1326,0.0601,0.0001,0.0,0.0052,0.0,1501.9,72.09,43.99,50.37
|
| 46 |
+
2026-02-18T11:00:00Z,4.8673,0.0,4.2057,0.4549,0.0075,0.1362,0.0599,0.0001,0.0,0.003,0.0,1523.8,73.14,42.84,50.38
|
| 47 |
+
2026-02-18T11:15:00Z,5.0185,0.0,4.3544,0.4637,0.0043,0.1363,0.058,0.0,0.0,0.0017,0.0,1546.5,74.23,44.75,50.35
|
| 48 |
+
2026-02-18T11:30:00Z,5.0904,0.0,4.4412,0.4503,0.0024,0.1328,0.0627,0.0,0.0,0.001,0.0,1569.6,75.34,41.87,50.44
|
| 49 |
+
2026-02-18T11:45:00Z,4.9529,0.0,4.2942,0.4593,0.0021,0.1351,0.0612,0.0,0.0,0.0008,0.0,1592.0,76.41,45.41,50.49
|
| 50 |
+
2026-02-18T12:00:00Z,4.9252,0.0,4.2666,0.4564,0.0021,0.1348,0.0644,0.0,0.0,0.0008,0.0,1614.2,77.48,43.79,50.73
|
| 51 |
+
2026-02-18T12:15:00Z,4.9515,0.0,4.2858,0.4651,0.0022,0.1348,0.0627,0.0,0.0,0.0009,0.0,1636.5,78.55,43.46,50.67
|
| 52 |
+
2026-02-18T12:30:00Z,4.8855,0.0,4.2247,0.4638,0.0022,0.1357,0.0582,0.0,0.0,0.0008,0.0,1658.5,79.61,41.75,50.79
|
| 53 |
+
2026-02-18T12:45:00Z,4.7808,0.0,4.1235,0.4556,0.0021,0.1357,0.063,0.0,0.0,0.0009,0.0,1680.0,80.64,45.85,50.77
|
| 54 |
+
2026-02-18T13:00:00Z,4.7031,0.0,4.0384,0.4628,0.0022,0.1362,0.0626,0.0,0.0,0.0008,0.0,1701.0,81.65,41.81,50.87
|
| 55 |
+
2026-02-18T13:15:00Z,4.6808,0.0,4.016,0.4676,0.0021,0.1355,0.0587,0.0,0.0,0.0008,0.0,1721.9,82.65,44.11,51.04
|
| 56 |
+
2026-02-18T13:30:00Z,4.5547,0.0,3.9081,0.4543,0.0022,0.1339,0.0554,0.0,0.0,0.0009,0.0,1742.3,83.63,42.06,50.95
|
| 57 |
+
2026-02-18T13:45:00Z,4.3837,0.0,3.7111,0.4709,0.0022,0.1358,0.0629,0.0,0.0,0.0008,0.0,1761.6,84.56,45.29,51.04
|
| 58 |
+
2026-02-18T14:00:00Z,4.2822,0.0,3.5967,0.4866,0.0021,0.1355,0.0605,0.0,0.0,0.0008,0.0,1780.4,85.46,42.67,51.09
|
| 59 |
+
2026-02-18T14:15:00Z,4.1572,0.0,3.4622,0.4924,0.0022,0.1362,0.0634,0.0,0.0,0.0008,0.0,1798.4,86.32,43.85,51.17
|
| 60 |
+
2026-02-18T14:30:00Z,3.8167,0.0,3.1125,0.505,0.0022,0.1348,0.0614,0.0,0.0,0.0008,0.0,1814.6,87.1,43.29,51.18
|
| 61 |
+
2026-02-18T14:45:00Z,3.7577,0.0,3.058,0.4962,0.0022,0.1375,0.063,0.0,0.0,0.0008,0.0,1830.5,87.87,42.67,51.3
|
| 62 |
+
2026-02-18T15:00:00Z,3.3135,0.0,2.5952,0.5215,0.0025,0.1349,0.0585,0.0,0.0,0.001,0.0,1844.0,88.51,43.62,51.29
|
| 63 |
+
2026-02-18T15:15:00Z,3.1505,0.0,2.4161,0.5342,0.004,0.1335,0.0611,0.0,0.0,0.0015,0.0,1856.6,89.12,44.39,51.24
|
| 64 |
+
2026-02-18T15:30:00Z,2.9524,0.0,2.2083,0.5366,0.006,0.1354,0.0637,0.0001,0.0,0.0023,0.0,1868.1,89.67,42.43,51.4
|
| 65 |
+
2026-02-18T15:45:00Z,2.6099,0.0,1.8451,0.5606,0.0091,0.1353,0.0562,0.0001,0.0,0.0035,0.0,1877.7,90.13,43.51,51.34
|
| 66 |
+
2026-02-18T16:00:00Z,2.3811,0.0,1.6161,0.5499,0.0137,0.1355,0.0603,0.0003,0.0,0.0053,0.0,1886.2,90.54,44.5,51.41
|
| 67 |
+
2026-02-18T16:15:00Z,2.0176,0.0,1.2219,0.5742,0.0196,0.1316,0.0619,0.0007,0.0,0.0077,0.0,1892.5,90.84,44.67,51.4
|
| 68 |
+
2026-02-18T16:30:00Z,1.7913,0.0,0.9673,0.5878,0.0277,0.1346,0.0618,0.0012,0.0,0.0109,0.0,1897.6,91.08,41.83,51.52
|
| 69 |
+
2026-02-18T16:45:00Z,1.47,0.0,0.6377,0.5815,0.0367,0.1355,0.062,0.002,0.0,0.0146,0.0,1900.9,91.24,44.65,51.45
|
| 70 |
+
2026-02-18T17:00:00Z,1.1324,0.0,0.2636,0.6012,0.0501,0.1354,0.0604,0.0034,0.0,0.0185,0.0,1902.3,91.31,44.43,51.53
|
| 71 |
+
2026-02-18T17:15:00Z,0.836,0.0,-0.7035,0.6164,0.0631,0.136,0.0649,0.0052,0.63,0.0239,0.0,1898.6,91.13,44.54,51.46
|
| 72 |
+
2026-02-18T17:30:00Z,0.5021,0.0,-2.0536,0.6296,0.0777,0.1361,0.0619,0.0079,1.6125,0.03,0.0,1887.9,90.62,44.88,51.52
|
| 73 |
+
2026-02-18T17:45:00Z,0.1751,0.0,-2.6996,0.6293,0.0954,0.1364,0.0679,0.0107,1.8983,0.0368,0.0,1873.8,89.94,43.13,51.39
|
| 74 |
+
2026-02-18T18:00:00Z,0.0,0.0,-3.4552,0.6313,0.114,0.1362,0.0632,0.0133,2.4542,0.0429,0.0,1855.8,89.08,0.0,51.3
|
| 75 |
+
2026-02-18T18:15:00Z,0.0,0.0,-3.6425,0.6472,0.1308,0.134,0.0603,0.017,2.6014,0.0516,0.0,1836.9,88.17,0.0,51.31
|
| 76 |
+
2026-02-18T18:30:00Z,0.0,0.0,-4.3965,0.6656,0.1447,0.1356,0.0597,0.0182,3.3159,0.0568,0.0,1814.0,87.07,0.0,51.3
|
| 77 |
+
2026-02-18T18:45:00Z,0.0,0.0,-4.5807,0.6603,0.1575,0.1366,0.0599,0.0187,3.4854,0.0624,0.0,1790.1,85.93,0.0,51.21
|
| 78 |
+
2026-02-18T19:00:00Z,0.0,0.0,-4.5989,0.6562,0.1669,0.135,0.0618,0.0194,3.4926,0.0671,0.0,1766.2,84.78,0.0,51.13
|
| 79 |
+
2026-02-18T19:15:00Z,0.0,0.0,-4.7505,0.6527,0.1733,0.1386,0.0652,0.0182,3.6374,0.0651,0.0,1741.4,83.59,0.0,51.03
|
| 80 |
+
2026-02-18T19:30:00Z,0.0,0.0,-4.6486,0.6344,0.1702,0.1346,0.062,0.0169,3.5598,0.0708,0.0,1717.2,82.43,0.0,51.0
|
| 81 |
+
2026-02-18T19:45:00Z,0.0,0.0,-4.3798,0.6494,0.1648,0.1376,0.0578,0.0133,3.2914,0.0655,0.0,1694.4,81.33,0.0,50.94
|
| 82 |
+
2026-02-18T20:00:00Z,0.0,0.0,-4.3565,0.6827,0.1601,0.1351,0.0634,0.0102,3.2427,0.0623,0.0,1671.7,80.24,0.0,50.86
|
| 83 |
+
2026-02-18T20:15:00Z,0.0,0.0,-4.1691,0.6546,0.1491,0.1355,0.0588,0.0079,3.1063,0.0569,0.0,1650.0,79.2,0.0,50.82
|
| 84 |
+
2026-02-18T20:30:00Z,0.0,0.0,-3.7595,0.6522,0.1304,0.1358,0.065,0.0054,2.7178,0.0528,0.0,1630.4,78.26,0.0,50.73
|
| 85 |
+
2026-02-18T20:45:00Z,0.0,0.0,-3.3481,0.6422,0.1137,0.1328,0.0649,0.0035,2.3489,0.0421,0.0,1613.0,77.42,0.0,50.66
|
| 86 |
+
2026-02-18T21:00:00Z,0.0,0.0,-2.8641,0.667,0.0956,0.136,0.0642,0.002,1.863,0.0364,0.0,1598.0,76.71,0.0,50.7
|
| 87 |
+
2026-02-18T21:15:00Z,0.0,0.0,-2.6264,0.6514,0.0794,0.1352,0.0584,0.0011,1.6704,0.0304,0.0,1584.4,76.05,0.0,50.64
|
| 88 |
+
2026-02-18T21:30:00Z,0.0,0.0,-1.6831,0.6542,0.0652,0.1376,0.0641,0.0007,0.7361,0.0252,0.0,1575.6,75.63,0.0,50.46
|
| 89 |
+
2026-02-18T21:45:00Z,0.0,0.0,-0.9166,0.6499,0.0505,0.1335,0.0628,0.0004,0.0,0.0196,0.0,1570.8,75.4,0.0,50.57
|
| 90 |
+
2026-02-18T22:00:00Z,0.0,0.0,-0.9243,0.6784,0.0377,0.1358,0.0572,0.0002,0.0,0.0151,0.0,1566.0,75.17,0.0,50.52
|
| 91 |
+
2026-02-18T22:15:00Z,0.0,0.0,-0.8679,0.6286,0.0281,0.136,0.064,0.0001,0.0,0.0111,0.0,1561.5,74.95,0.0,50.48
|
| 92 |
+
2026-02-18T22:30:00Z,0.0,0.0,-0.872,0.6489,0.0203,0.137,0.0579,0.0,0.0,0.0079,0.0,1557.0,74.73,0.0,50.47
|
| 93 |
+
2026-02-18T22:45:00Z,0.0,0.0,-0.8408,0.6286,0.0139,0.1336,0.0594,0.0,0.0,0.0053,0.0,1552.6,74.52,0.0,50.5
|
| 94 |
+
2026-02-18T23:00:00Z,0.0,0.0,-0.8581,0.6504,0.0026,0.1348,0.0668,0.0,0.0,0.0035,0.0,1548.1,74.31,0.0,50.42
|
| 95 |
+
2026-02-18T23:15:00Z,0.0,0.0,-0.86,0.6595,0.002,0.1339,0.0621,0.0,0.0,0.0025,0.0,1543.6,74.09,0.0,50.4
|
| 96 |
+
2026-02-18T23:30:00Z,0.0,0.0,-0.8734,0.6718,0.002,0.1362,0.0618,0.0,0.0,0.0016,0.0,1539.1,73.88,0.0,50.43
|
| 97 |
+
2026-02-18T23:45:00Z,0.0,0.0,-0.8557,0.659,0.002,0.1363,0.0574,0.0,0.0,0.001,0.0,1534.6,73.66,0.0,50.41
|
| 98 |
+
2026-02-19T00:00:00Z,0.0,0.0,-0.853,0.6484,0.002,0.1368,0.0649,0.0,0.0,0.0009,0.0,1530.2,73.45,0.0,50.4
|
| 99 |
+
2026-02-19T00:15:00Z,0.0,0.0,-0.8754,0.6726,0.002,0.1382,0.0618,0.0,0.0,0.0008,0.0,1525.6,73.23,0.0,50.4
|
| 100 |
+
2026-02-19T00:30:00Z,0.0,0.0,-0.8626,0.6603,0.002,0.1359,0.0636,0.0,0.0,0.0008,0.0,1521.1,73.01,0.0,50.41
|
| 101 |
+
2026-02-19T00:45:00Z,0.0,0.0,-0.8665,0.6613,0.002,0.1359,0.0665,0.0,0.0,0.0008,0.0,1516.6,72.8,0.0,50.4
|
| 102 |
+
2026-02-19T01:00:00Z,0.0,0.0,-0.846,0.6454,0.002,0.1361,0.0617,0.0,0.0,0.0008,0.0,1512.2,72.59,0.0,50.3
|
| 103 |
+
2026-02-19T01:15:00Z,0.0,0.0,-0.8622,0.6634,0.002,0.1348,0.061,0.0,0.0,0.0009,0.0,1507.7,72.37,0.0,50.37
|
| 104 |
+
2026-02-19T01:30:00Z,0.0,0.0,-0.8342,0.6305,0.002,0.1351,0.0657,0.0,0.0,0.0009,0.0,1503.4,72.16,0.0,50.27
|
| 105 |
+
2026-02-19T01:45:00Z,0.0,0.0,-0.8356,0.6393,0.002,0.1355,0.0579,0.0,0.0,0.0008,0.0,1499.0,71.95,0.0,50.31
|
| 106 |
+
2026-02-19T02:00:00Z,0.0,0.0,-0.8687,0.6669,0.002,0.1351,0.0638,0.0,0.0,0.0009,0.0,1494.5,71.74,0.0,50.37
|
| 107 |
+
2026-02-19T02:15:00Z,0.0,0.0,-0.8779,0.678,0.002,0.1368,0.0603,0.0,0.0,0.0008,0.0,1489.9,71.52,0.0,50.18
|
| 108 |
+
2026-02-19T02:30:00Z,0.0,0.0,-0.8225,0.6243,0.002,0.1325,0.0628,0.0,0.0,0.0008,0.0,1485.6,71.31,0.0,50.29
|
| 109 |
+
2026-02-19T02:45:00Z,0.0,0.0,-0.8674,0.6624,0.002,0.1366,0.0656,0.0,0.0,0.0009,0.0,1481.1,71.09,0.0,50.35
|
| 110 |
+
2026-02-19T03:00:00Z,0.0,0.0,-0.83,0.63,0.002,0.1351,0.0621,0.0,0.0,0.0008,0.0,1476.8,70.89,0.0,50.29
|
| 111 |
+
2026-02-19T03:15:00Z,0.0,0.0,-0.8377,0.633,0.002,0.1362,0.0656,0.0,0.0,0.0008,0.0,1472.4,70.68,0.0,50.2
|
| 112 |
+
2026-02-19T03:30:00Z,0.0,0.0,-0.8456,0.6488,0.002,0.1327,0.0613,0.0,0.0,0.0009,0.0,1468.0,70.47,0.0,50.31
|
| 113 |
+
2026-02-19T03:45:00Z,0.0,0.0,-0.8576,0.656,0.002,0.1316,0.0671,0.0,0.0,0.0008,0.0,1463.6,70.25,0.0,50.19
|
| 114 |
+
2026-02-19T04:00:00Z,0.0,0.0,-0.8808,0.6729,0.002,0.1366,0.0684,0.0001,0.0,0.0008,0.0,1459.0,70.03,0.0,50.19
|
| 115 |
+
2026-02-19T04:15:00Z,0.0,0.0,-0.8554,0.655,0.002,0.1369,0.0603,0.0003,0.0,0.0009,0.0,1454.5,69.82,0.0,50.26
|
| 116 |
+
2026-02-19T04:30:00Z,0.0,0.0,-0.8755,0.6702,0.002,0.1365,0.0647,0.0005,0.0,0.0016,0.0,1450.0,69.6,0.0,50.15
|
| 117 |
+
2026-02-19T04:45:00Z,0.0,0.0,-0.8527,0.6513,0.002,0.1367,0.0589,0.001,0.0,0.0027,0.0,1445.5,69.38,0.0,50.22
|
| 118 |
+
2026-02-19T05:00:00Z,0.0,0.0,-0.8641,0.656,0.002,0.1363,0.0634,0.0019,0.0,0.0046,0.0,1441.0,69.17,0.0,50.14
|
| 119 |
+
2026-02-19T05:15:00Z,0.0,0.0,-0.8655,0.6566,0.002,0.1345,0.0615,0.0035,0.0,0.0073,0.0,1436.5,68.95,0.0,50.12
|
| 120 |
+
2026-02-19T05:30:00Z,0.0,0.0,-0.8753,0.6648,0.002,0.1346,0.0574,0.0053,0.0,0.0113,0.0,1432.0,68.73,0.0,50.15
|
| 121 |
+
2026-02-19T05:45:00Z,0.0,0.0,-0.8667,0.642,0.002,0.1379,0.0596,0.0084,0.0,0.0168,0.0,1427.4,68.52,0.0,50.11
|
| 122 |
+
2026-02-19T06:00:00Z,0.151,0.0,-1.2821,0.6498,0.0634,0.1362,0.0578,0.0134,0.4868,0.0256,0.0,1420.8,68.2,41.37,50.07
|
| 123 |
+
2026-02-19T06:15:00Z,0.4775,0.0,-2.4468,0.638,0.0868,0.1351,0.0655,0.0176,1.9487,0.0326,0.0,1408.0,67.58,43.63,50.05
|
| 124 |
+
2026-02-19T06:30:00Z,0.7803,0.0,-2.6627,0.6168,0.1113,0.1366,0.061,0.0213,2.4523,0.0437,0.0,1394.1,66.92,44.13,49.97
|
| 125 |
+
2026-02-19T06:45:00Z,1.1081,0.0,-3.018,0.5831,0.1376,0.1357,0.0639,0.0285,3.1206,0.0567,0.0,1378.4,66.16,43.37,50.03
|
| 126 |
+
2026-02-19T07:00:00Z,1.4704,0.0,-2.8918,0.5869,0.1675,0.1345,0.0602,0.0309,3.3171,0.0649,0.0,1363.4,65.44,44.73,50.01
|
| 127 |
+
2026-02-19T07:15:00Z,1.7488,0.0,-3.4629,0.5879,0.1853,0.138,0.0656,0.0327,4.1281,0.0742,0.0,1345.3,64.58,43.93,49.83
|
| 128 |
+
2026-02-19T07:30:00Z,2.0456,0.0,-3.4529,0.5864,0.2046,0.1345,0.0646,0.0341,4.3971,0.0772,0.0,1327.3,63.71,45.83,49.79
|
| 129 |
+
2026-02-19T07:45:00Z,2.3915,0.0,-3.4549,0.5637,0.2117,0.1354,0.057,0.0324,4.7636,0.0828,0.0,1309.4,62.85,45.95,49.81
|
| 130 |
+
2026-02-19T08:00:00Z,2.6762,0.0,-2.7634,0.5642,0.2138,0.1335,0.0564,0.0282,4.359,0.0845,0.0,1295.0,62.16,43.59,49.79
|
| 131 |
+
2026-02-19T08:15:00Z,2.9406,0.0,-2.4264,0.5285,0.2009,0.1363,0.0602,0.022,4.3391,0.0799,0.0,1282.3,61.55,43.58,49.69
|
| 132 |
+
2026-02-19T08:30:00Z,3.1321,0.0,-1.7445,0.5518,0.1848,0.1337,0.06,0.0186,3.8541,0.0736,0.0,1273.2,61.12,44.49,49.58
|
| 133 |
+
2026-02-19T08:45:00Z,3.342,0.0,-1.2096,0.5121,0.1629,0.1345,0.0619,0.0125,3.6042,0.0634,0.0,1266.9,60.81,42.97,49.54
|
| 134 |
+
2026-02-19T09:00:00Z,3.537,0.0,-0.3748,0.5034,0.1419,0.1363,0.0595,0.0087,3.01,0.052,0.0,1265.0,60.72,44.05,49.68
|
| 135 |
+
2026-02-19T09:15:00Z,3.9344,0.0,0.7336,0.4912,0.1119,0.1352,0.0646,0.0056,2.347,0.0454,0.0,1268.8,60.9,45.27,49.49
|
| 136 |
+
2026-02-19T09:30:00Z,4.1323,0.0,1.4221,0.4931,0.0878,0.1374,0.0598,0.0036,1.8946,0.0339,0.0,1276.2,61.26,45.26,49.71
|
| 137 |
+
2026-02-19T09:45:00Z,4.1663,0.0,2.6938,0.4994,0.0661,0.1376,0.0616,0.002,0.6813,0.0244,0.0,1290.2,61.93,43.17,49.67
|
| 138 |
+
2026-02-19T10:00:00Z,4.4393,0.0,3.7015,0.4711,0.0459,0.1389,0.0623,0.0012,0.0,0.0184,0.0,1309.5,62.86,44.59,49.77
|
| 139 |
+
2026-02-19T10:15:00Z,4.5702,0.0,3.8532,0.4764,0.0305,0.1358,0.0617,0.0005,0.0,0.0122,0.0,1329.6,63.82,43.44,49.88
|
| 140 |
+
2026-02-19T10:30:00Z,4.6637,0.0,3.954,0.486,0.0202,0.1352,0.0601,0.0003,0.0,0.008,0.0,1350.2,64.81,45.92,49.86
|
| 141 |
+
2026-02-19T10:45:00Z,4.8317,0.0,4.145,0.4698,0.0122,0.1326,0.0669,0.0001,0.0,0.0051,0.0,1371.8,65.85,44.78,49.9
|
| 142 |
+
2026-02-19T11:00:00Z,4.8247,0.0,4.1506,0.4696,0.0074,0.1367,0.0575,0.0,0.0,0.0028,0.0,1393.4,66.88,44.1,50.0
|
| 143 |
+
2026-02-19T11:15:00Z,4.7725,0.0,4.1173,0.4532,0.0043,0.1348,0.0613,0.0,0.0,0.0017,0.0,1414.8,67.91,43.47,50.16
|
| 144 |
+
2026-02-19T11:30:00Z,4.8855,0.0,4.2361,0.4523,0.0025,0.1333,0.0602,0.0,0.0,0.001,0.0,1436.9,68.97,40.56,50.14
|
| 145 |
+
2026-02-19T11:45:00Z,4.867,0.0,4.2149,0.4555,0.0022,0.1367,0.0569,0.0,0.0,0.0008,0.0,1458.9,70.02,46.41,50.25
|
| 146 |
+
2026-02-19T12:00:00Z,5.0259,0.0,4.3716,0.4532,0.0022,0.1366,0.0616,0.0,0.0,0.0009,0.0,1481.6,71.12,44.86,50.32
|
| 147 |
+
2026-02-19T12:15:00Z,5.0283,0.0,4.3763,0.4516,0.0022,0.1343,0.0631,0.0,0.0,0.0008,0.0,1504.4,72.21,43.05,50.17
|
| 148 |
+
2026-02-19T12:30:00Z,4.912,0.0,4.2739,0.4419,0.0022,0.1351,0.058,0.0,0.0,0.0009,0.0,1526.7,73.28,42.49,50.32
|
| 149 |
+
2026-02-19T12:45:00Z,4.9445,0.0,4.2892,0.4554,0.0021,0.1346,0.0623,0.0,0.0,0.0009,0.0,1549.0,74.35,41.94,50.43
|
| 150 |
+
2026-02-19T13:00:00Z,4.7993,0.0,4.1451,0.4573,0.0022,0.1341,0.0598,0.0,0.0,0.0009,0.0,1570.6,75.39,44.35,50.49
|
| 151 |
+
2026-02-19T13:15:00Z,4.6388,0.0,3.9683,0.4684,0.0022,0.135,0.0642,0.0,0.0,0.0008,0.0,1591.3,76.38,46.4,50.62
|
| 152 |
+
2026-02-19T13:30:00Z,4.4508,0.0,3.7796,0.4737,0.0022,0.1369,0.0576,0.0,0.0,0.0008,0.0,1611.0,77.33,43.07,50.52
|
| 153 |
+
2026-02-19T13:45:00Z,4.4633,0.0,3.7787,0.482,0.0022,0.1335,0.0662,0.0,0.0,0.0009,0.0,1630.6,78.27,42.25,50.65
|
| 154 |
+
2026-02-19T14:00:00Z,4.2152,0.0,3.537,0.4763,0.0022,0.1356,0.0634,0.0,0.0,0.0008,0.0,1649.1,79.15,45.06,50.72
|
| 155 |
+
2026-02-19T14:15:00Z,4.0671,0.0,3.3705,0.4989,0.0021,0.1325,0.0622,0.0,0.0,0.0008,0.0,1666.6,80.0,44.15,50.78
|
| 156 |
+
2026-02-19T14:30:00Z,3.8031,0.0,3.0939,0.5078,0.0021,0.1359,0.0626,0.0,0.0,0.0008,0.0,1682.7,80.77,42.32,50.85
|
| 157 |
+
2026-02-19T14:45:00Z,3.629,0.0,2.921,0.5112,0.0021,0.1338,0.06,0.0,0.0,0.0008,0.0,1697.9,81.5,42.59,50.87
|
| 158 |
+
2026-02-19T15:00:00Z,3.4211,0.0,2.7079,0.5152,0.0026,0.1362,0.0583,0.0,0.0,0.001,0.0,1712.0,82.18,43.21,50.9
|
| 159 |
+
2026-02-19T15:15:00Z,3.1851,0.0,2.4619,0.5244,0.0039,0.1347,0.0587,0.0,0.0,0.0015,0.0,1724.9,82.79,44.86,50.91
|
| 160 |
+
2026-02-19T15:30:00Z,2.8646,0.0,2.1215,0.5357,0.0061,0.1346,0.0641,0.0001,0.0,0.0025,0.0,1735.9,83.32,44.33,50.93
|
| 161 |
+
2026-02-19T15:45:00Z,2.6475,0.0,1.9141,0.5291,0.0093,0.1341,0.0573,0.0001,0.0,0.0036,0.0,1745.9,83.8,43.93,51.03
|
| 162 |
+
2026-02-19T16:00:00Z,2.4057,0.0,1.6514,0.541,0.0134,0.1375,0.0569,0.0003,0.0,0.0053,0.0,1754.5,84.22,43.79,51.02
|
| 163 |
+
2026-02-19T16:15:00Z,1.998,0.0,1.2166,0.5593,0.0198,0.135,0.059,0.0006,0.0,0.0078,0.0,1760.8,84.52,45.74,51.02
|
| 164 |
+
2026-02-19T16:30:00Z,1.7708,0.0,0.961,0.5715,0.0278,0.1358,0.0628,0.0011,0.0,0.0109,0.0,1765.8,84.76,43.04,51.06
|
| 165 |
+
2026-02-19T16:45:00Z,1.4335,0.0,0.574,0.6071,0.0373,0.1387,0.0603,0.0021,0.0,0.014,0.0,1768.8,84.9,44.73,51.09
|
| 166 |
+
2026-02-19T17:00:00Z,1.1409,0.0,0.2828,0.5912,0.0483,0.1356,0.0608,0.0033,0.0,0.0188,0.0,1770.3,84.97,43.15,51.18
|
| 167 |
+
2026-02-19T17:15:00Z,0.8126,0.0,-0.6251,0.6215,0.0641,0.1355,0.0603,0.0048,0.5263,0.0253,0.0,1767.0,84.82,44.37,51.03
|
| 168 |
+
2026-02-19T17:30:00Z,0.5027,0.0,-2.1382,0.6356,0.079,0.1369,0.0614,0.0077,1.6912,0.029,0.0,1755.9,84.28,44.4,51.09
|
| 169 |
+
2026-02-19T17:45:00Z,0.1801,0.0,-2.9472,0.6357,0.0979,0.1372,0.0626,0.0103,2.1469,0.0368,0.0,1740.5,83.55,43.03,51.12
|
| 170 |
+
2026-02-19T18:00:00Z,0.0,0.0,-3.464,0.6688,0.1148,0.1372,0.057,0.0135,2.4284,0.0443,0.0,1722.5,82.68,0.0,50.92
|
| 171 |
+
2026-02-19T18:15:00Z,0.0,0.0,-3.8771,0.646,0.1275,0.1348,0.0619,0.0166,2.8402,0.05,0.0,1702.3,81.71,0.0,50.9
|
| 172 |
+
2026-02-19T18:30:00Z,0.0,0.0,-3.9866,0.6461,0.1467,0.1344,0.0642,0.0184,2.9194,0.0574,0.0,1681.5,80.71,0.0,50.86
|
| 173 |
+
2026-02-19T18:45:00Z,0.0,0.0,-4.5255,0.6573,0.1578,0.1342,0.0609,0.0201,3.4354,0.0598,0.0,1658.0,79.58,0.0,50.68
|
| 174 |
+
2026-02-19T19:00:00Z,0.0,0.0,-4.4537,0.6799,0.1673,0.1352,0.061,0.0201,3.3248,0.0655,0.0,1634.8,78.47,0.0,50.78
|
| 175 |
+
2026-02-19T19:15:00Z,0.0,0.0,-4.8467,0.6524,0.1732,0.1355,0.0638,0.0176,3.7381,0.0661,0.0,1609.5,77.26,0.0,50.67
|
| 176 |
+
2026-02-19T19:30:00Z,0.0,0.0,-5.0059,0.6548,0.1725,0.1376,0.0627,0.0154,3.8971,0.0659,0.0,1583.5,76.01,0.0,50.53
|
| 177 |
+
2026-02-19T19:45:00Z,0.0,0.0,-4.5128,0.6535,0.1715,0.1371,0.0629,0.0137,3.407,0.0671,0.0,1560.0,74.88,0.0,50.5
|
| 178 |
+
2026-02-19T20:00:00Z,0.0,0.0,-4.1913,0.6576,0.1577,0.1354,0.0609,0.0106,3.1104,0.0587,0.0,1538.1,73.83,0.0,50.5
|
| 179 |
+
2026-02-19T20:15:00Z,0.0,0.0,-4.3798,0.6311,0.1456,0.1348,0.0645,0.008,3.3406,0.0552,0.0,1515.3,72.74,0.0,50.47
|
| 180 |
+
2026-02-19T20:30:00Z,0.0,0.0,-3.6585,0.6517,0.1289,0.1343,0.0622,0.0053,2.6246,0.0515,0.0,1496.3,71.82,0.0,50.27
|
| 181 |
+
2026-02-19T20:45:00Z,0.0,0.0,-3.5839,0.6436,0.1128,0.1338,0.0603,0.0033,2.5876,0.0426,0.0,1477.6,70.92,0.0,50.32
|
| 182 |
+
2026-02-19T21:00:00Z,0.0,0.0,-2.9842,0.6536,0.0973,0.1356,0.0636,0.002,1.9956,0.0365,0.0,1462.1,70.18,0.0,50.22
|
| 183 |
+
2026-02-19T21:15:00Z,0.0,0.0,-2.6737,0.6471,0.0798,0.1358,0.0629,0.0012,1.7157,0.0312,0.0,1448.1,69.51,0.0,50.2
|
| 184 |
+
2026-02-19T21:30:00Z,0.0,0.0,-1.5066,0.6371,0.0657,0.1341,0.069,0.0006,0.5752,0.025,0.0,1440.3,69.13,0.0,50.23
|
| 185 |
+
2026-02-19T21:45:00Z,0.0,0.0,-0.9008,0.6381,0.0498,0.1337,0.0601,0.0004,0.0,0.0187,0.0,1435.6,68.91,0.0,50.18
|
| 186 |
+
2026-02-19T22:00:00Z,0.0,0.0,-0.9283,0.6754,0.0378,0.1359,0.064,0.0001,0.0,0.0149,0.0,1430.8,68.68,0.0,50.27
|
| 187 |
+
2026-02-19T22:15:00Z,0.0,0.0,-0.9041,0.6643,0.0285,0.1361,0.0646,0.0001,0.0,0.0105,0.0,1426.1,68.45,0.0,50.11
|
| 188 |
+
2026-02-19T22:30:00Z,0.0,0.0,-0.8656,0.6401,0.0198,0.1326,0.0651,0.0,0.0,0.008,0.0,1421.5,68.23,0.0,50.07
|
| 189 |
+
2026-02-19T22:45:00Z,0.0,0.0,-0.8719,0.6612,0.014,0.1341,0.057,0.0,0.0,0.0056,0.0,1417.0,68.02,0.0,50.04
|
| 190 |
+
2026-02-19T23:00:00Z,0.0,0.0,-0.8407,0.6349,0.0026,0.1346,0.065,0.0,0.0,0.0036,0.0,1412.6,67.81,0.0,49.96
|
| 191 |
+
2026-02-19T23:15:00Z,0.0,0.0,-0.857,0.6568,0.002,0.1357,0.0601,0.0,0.0,0.0024,0.0,1408.2,67.59,0.0,50.08
|
| 192 |
+
2026-02-19T23:30:00Z,0.0,0.0,-0.8693,0.669,0.002,0.1357,0.0612,0.0,0.0,0.0015,0.0,1403.6,67.37,0.0,50.07
|
| 193 |
+
2026-02-19T23:45:00Z,0.0,0.0,-0.8568,0.6625,0.002,0.1345,0.0569,0.0,0.0,0.0009,0.0,1399.2,67.16,0.0,50.04
|
| 194 |
+
2026-02-20T00:00:00Z,0.0,0.0,-0.8644,0.6711,0.002,0.1341,0.0563,0.0,0.0,0.0009,0.0,1394.7,66.94,0.0,50.03
|
| 195 |
+
2026-02-20T00:15:00Z,0.0,0.0,-0.86,0.6576,0.002,0.1376,0.0621,0.0,0.0,0.0008,0.0,1390.2,66.73,0.0,49.96
|
| 196 |
+
2026-02-20T00:30:00Z,0.0,0.0,-0.8394,0.6298,0.002,0.1361,0.0707,0.0,0.0,0.0009,0.0,1385.8,66.52,0.0,50.03
|
| 197 |
+
2026-02-20T00:45:00Z,0.0,0.0,-0.8505,0.6432,0.002,0.1374,0.0671,0.0,0.0,0.0008,0.0,1381.4,66.31,0.0,50.02
|
| 198 |
+
2026-02-20T01:00:00Z,0.0,0.0,-0.8738,0.6722,0.002,0.1357,0.063,0.0,0.0,0.0008,0.0,1376.8,66.09,0.0,49.97
|
| 199 |
+
2026-02-20T01:15:00Z,0.0,0.0,-0.8157,0.6152,0.002,0.1342,0.0635,0.0,0.0,0.0008,0.0,1372.6,65.88,0.0,49.97
|
| 200 |
+
2026-02-20T01:30:00Z,0.0,0.0,-0.8524,0.6533,0.002,0.1341,0.0621,0.0,0.0,0.0008,0.0,1368.1,65.67,0.0,49.91
|
| 201 |
+
2026-02-20T01:45:00Z,0.0,0.0,-0.8368,0.6396,0.002,0.1353,0.0591,0.0,0.0,0.0008,0.0,1363.8,65.46,0.0,49.91
|
| 202 |
+
2026-02-20T02:00:00Z,0.0,0.0,-0.8412,0.6442,0.002,0.1346,0.0595,0.0,0.0,0.0008,0.0,1359.4,65.25,0.0,49.95
|
| 203 |
+
2026-02-20T02:15:00Z,0.0,0.0,-0.8453,0.6436,0.002,0.1352,0.0637,0.0,0.0,0.0008,0.0,1355.0,65.04,0.0,49.94
|
| 204 |
+
2026-02-20T02:30:00Z,0.0,0.0,-0.8495,0.6498,0.002,0.1354,0.0615,0.0,0.0,0.0008,0.0,1350.6,64.83,0.0,49.86
|
| 205 |
+
2026-02-20T02:45:00Z,0.0,0.0,-0.8541,0.6582,0.002,0.1352,0.0579,0.0,0.0,0.0009,0.0,1346.1,64.61,0.0,49.95
|
| 206 |
+
2026-02-20T03:00:00Z,0.0,0.0,-0.8298,0.6329,0.002,0.1327,0.0614,0.0,0.0,0.0009,0.0,1341.8,64.41,0.0,49.83
|
| 207 |
+
2026-02-20T03:15:00Z,0.0,0.0,-0.8653,0.6606,0.002,0.1366,0.0652,0.0,0.0,0.0009,0.0,1337.3,64.19,0.0,49.9
|
| 208 |
+
2026-02-20T03:30:00Z,0.0,0.0,-0.8297,0.6302,0.002,0.134,0.0626,0.0,0.0,0.0008,0.0,1333.0,63.98,0.0,49.84
|
| 209 |
+
2026-02-20T03:45:00Z,0.0,0.0,-0.8444,0.6429,0.002,0.1335,0.065,0.0,0.0,0.0009,0.0,1328.6,63.77,0.0,49.89
|
| 210 |
+
2026-02-20T04:00:00Z,0.0,0.0,-0.8558,0.6562,0.002,0.1359,0.0608,0.0001,0.0,0.0008,0.0,1324.1,63.56,0.0,49.81
|
| 211 |
+
2026-02-20T04:15:00Z,0.0,0.0,-0.8199,0.6192,0.002,0.1348,0.0627,0.0003,0.0,0.0009,0.0,1319.9,63.35,0.0,49.85
|
| 212 |
+
2026-02-20T04:30:00Z,0.0,0.0,-0.8429,0.6411,0.002,0.1355,0.0622,0.0005,0.0,0.0016,0.0,1315.5,63.14,0.0,49.7
|
| 213 |
+
2026-02-20T04:45:00Z,0.0,0.0,-0.8634,0.6617,0.002,0.1341,0.0617,0.001,0.0,0.0029,0.0,1311.0,62.93,0.0,49.78
|
| 214 |
+
2026-02-20T05:00:00Z,0.0,0.0,-0.8395,0.6395,0.002,0.132,0.0596,0.002,0.0,0.0045,0.0,1306.6,62.72,0.0,49.74
|
| 215 |
+
2026-02-20T05:15:00Z,0.0,0.0,-0.8714,0.6576,0.002,0.1363,0.0642,0.0036,0.0,0.0078,0.0,1302.1,62.5,0.0,49.67
|
| 216 |
+
2026-02-20T05:30:00Z,0.0,0.0,-0.859,0.6463,0.002,0.1361,0.0581,0.0053,0.0,0.0112,0.0,1297.6,62.28,0.0,49.78
|
| 217 |
+
2026-02-20T05:45:00Z,0.0,0.0,-0.8886,0.6666,0.002,0.1351,0.0577,0.0093,0.0,0.0179,0.0,1293.0,62.06,0.0,49.71
|
| 218 |
+
2026-02-20T06:00:00Z,0.1519,0.0,-1.3372,0.6412,0.0642,0.1352,0.0631,0.0129,0.5487,0.0237,0.0,1286.0,61.73,41.86,49.69
|
| 219 |
+
2026-02-20T06:15:00Z,0.4661,0.0,-2.3492,0.6538,0.086,0.1331,0.0665,0.018,1.8238,0.0341,0.0,1273.8,61.14,43.94,49.65
|
| 220 |
+
2026-02-20T06:30:00Z,0.8079,0.0,-2.5474,0.614,0.1108,0.1327,0.0596,0.0224,2.3727,0.0431,0.0,1260.5,60.5,43.72,49.65
|
| 221 |
+
2026-02-20T06:45:00Z,1.1612,0.0,-2.6783,0.6373,0.1383,0.1335,0.0619,0.0267,2.7895,0.0523,0.0,1246.5,59.83,42.54,49.53
|
| 222 |
+
2026-02-20T07:00:00Z,1.4431,0.0,-3.0125,0.5961,0.1609,0.1345,0.0601,0.031,3.4061,0.0669,0.0,1230.8,59.08,44.15,49.45
|
| 223 |
+
2026-02-20T07:15:00Z,1.6767,0.0,-3.1841,0.5912,0.185,0.137,0.0586,0.0327,3.7829,0.0734,0.0,1214.3,58.28,43.29,49.53
|
| 224 |
+
2026-02-20T07:30:00Z,2.0663,0.0,-3.8276,0.5874,0.2012,0.134,0.0624,0.0311,4.7974,0.0804,0.0,1194.3,57.33,44.95,49.5
|
| 225 |
+
2026-02-20T07:45:00Z,2.3645,0.0,-3.1065,0.5521,0.2144,0.1328,0.06,0.0314,4.3995,0.0808,0.0,1178.1,56.55,43.33,49.37
|
| 226 |
+
2026-02-20T08:00:00Z,2.669,0.0,-2.5511,0.5639,0.2162,0.138,0.0617,0.0284,4.129,0.0829,0.0,1164.9,55.91,42.45,49.46
|
| 227 |
+
2026-02-20T08:15:00Z,2.9262,0.0,-2.436,0.5114,0.1996,0.1357,0.0577,0.0223,4.3571,0.0786,0.0,1152.2,55.3,45.07,49.31
|
| 228 |
+
2026-02-20T08:30:00Z,3.2404,0.0,-1.6817,0.522,0.1893,0.1352,0.0655,0.0167,3.9177,0.0756,0.0,1143.4,54.88,43.9,49.34
|
| 229 |
+
2026-02-20T08:45:00Z,3.4333,0.0,-1.0655,0.5109,0.1689,0.1336,0.0637,0.0132,3.5454,0.0631,0.0,1137.9,54.62,43.49,49.24
|
| 230 |
+
2026-02-20T09:00:00Z,3.5487,0.0,-0.5474,0.5153,0.1417,0.1339,0.064,0.0089,3.1772,0.055,0.0,1135.0,54.48,43.46,49.22
|
| 231 |
+
2026-02-20T09:15:00Z,3.9054,0.0,0.5971,0.503,0.1149,0.135,0.0658,0.0055,2.4413,0.0428,0.0,1138.1,54.63,45.03,49.13
|
| 232 |
+
2026-02-20T09:30:00Z,4.0322,0.0,1.0954,0.4976,0.0869,0.1338,0.0585,0.0035,2.1229,0.0336,0.0,1143.8,54.9,43.66,49.3
|
| 233 |
+
2026-02-20T09:45:00Z,4.2096,0.0,2.7576,0.4893,0.0647,0.1348,0.0627,0.0021,0.674,0.0245,0.0,1158.2,55.59,46.59,49.32
|
| 234 |
+
2026-02-20T10:00:00Z,4.4915,0.0,3.7608,0.4683,0.0448,0.134,0.0648,0.0011,0.0,0.0177,0.0,1177.8,56.53,43.26,49.43
|
| 235 |
+
2026-02-20T10:15:00Z,4.4647,0.0,3.7439,0.4807,0.0316,0.1335,0.0629,0.0005,0.0,0.0116,0.0,1197.3,57.47,44.01,49.39
|
| 236 |
+
2026-02-20T10:30:00Z,4.7062,0.0,4.0028,0.4785,0.0201,0.1365,0.06,0.0003,0.0,0.008,0.0,1218.1,58.47,42.87,49.59
|
| 237 |
+
2026-02-20T10:45:00Z,4.8748,0.0,4.1874,0.4697,0.0129,0.1368,0.0629,0.0001,0.0,0.0051,0.0,1239.9,59.52,41.91,49.48
|
| 238 |
+
2026-02-20T11:00:00Z,4.8785,0.0,4.2066,0.4676,0.0075,0.1337,0.0601,0.0,0.0,0.0029,0.0,1261.8,60.57,45.06,49.63
|
| 239 |
+
2026-02-20T11:15:00Z,4.9486,0.0,4.2907,0.4574,0.0042,0.1348,0.0599,0.0,0.0,0.0017,0.0,1284.2,61.64,44.57,49.7
|
| 240 |
+
2026-02-20T11:30:00Z,5.0652,0.0,4.4032,0.4597,0.0024,0.1368,0.062,0.0,0.0,0.001,0.0,1307.1,62.74,43.31,49.82
|
| 241 |
+
2026-02-20T11:45:00Z,5.0904,0.0,4.4294,0.4575,0.0022,0.1353,0.0653,0.0,0.0,0.0008,0.0,1330.2,63.85,41.33,49.85
|
| 242 |
+
2026-02-20T12:00:00Z,4.9286,0.0,4.2685,0.461,0.0021,0.1351,0.061,0.0,0.0,0.0008,0.0,1352.4,64.92,43.93,49.82
|
| 243 |
+
2026-02-20T12:15:00Z,4.912,0.0,4.2462,0.4675,0.0022,0.1358,0.0594,0.0,0.0,0.0009,0.0,1374.5,65.98,44.32,49.97
|
| 244 |
+
2026-02-20T12:30:00Z,4.8945,0.0,4.235,0.456,0.0022,0.1365,0.0639,0.0,0.0,0.0008,0.0,1396.6,67.04,42.25,50.04
|
| 245 |
+
2026-02-20T12:45:00Z,4.9222,0.0,4.2501,0.4715,0.0022,0.136,0.0615,0.0,0.0,0.0008,0.0,1418.7,68.1,43.26,50.14
|
| 246 |
+
2026-02-20T13:00:00Z,4.9169,0.0,4.2344,0.4782,0.0021,0.1353,0.0661,0.0,0.0,0.0008,0.0,1440.8,69.16,43.29,50.09
|
| 247 |
+
2026-02-20T13:15:00Z,4.6886,0.0,4.0226,0.4687,0.0022,0.1352,0.0592,0.0,0.0,0.0009,0.0,1461.7,70.16,41.79,50.18
|
| 248 |
+
2026-02-20T13:30:00Z,4.6055,0.0,3.9232,0.4864,0.0022,0.1341,0.0588,0.0,0.0,0.0008,0.0,1482.2,71.14,43.74,50.12
|
| 249 |
+
2026-02-20T13:45:00Z,4.4171,0.0,3.729,0.4868,0.0022,0.1344,0.0639,0.0,0.0,0.0008,0.0,1501.6,72.08,41.35,50.2
|
| 250 |
+
2026-02-20T14:00:00Z,4.1494,0.0,3.4804,0.4728,0.0021,0.1334,0.0598,0.0,0.0,0.0008,0.0,1519.7,72.95,41.69,50.42
|
| 251 |
+
2026-02-20T14:15:00Z,4.0716,0.0,3.3777,0.49,0.0022,0.1361,0.0649,0.0,0.0,0.0008,0.0,1537.3,73.79,42.66,50.38
|
| 252 |
+
2026-02-20T14:30:00Z,3.8596,0.0,3.1591,0.4996,0.0022,0.1342,0.0636,0.0,0.0,0.0009,0.0,1553.8,74.58,44.94,50.5
|
| 253 |
+
2026-02-20T14:45:00Z,3.755,0.0,3.0402,0.5117,0.0022,0.1366,0.0635,0.0,0.0,0.0008,0.0,1569.6,75.34,42.21,50.45
|
| 254 |
+
2026-02-20T15:00:00Z,3.4313,0.0,2.7122,0.5189,0.0025,0.1353,0.0613,0.0,0.0,0.001,0.0,1583.7,76.02,42.67,50.62
|
| 255 |
+
2026-02-20T15:15:00Z,3.2411,0.0,2.5225,0.5196,0.0039,0.1338,0.0597,0.0,0.0,0.0016,0.0,1596.9,76.65,44.18,50.63
|
| 256 |
+
2026-02-20T15:30:00Z,2.995,0.0,2.2834,0.5087,0.0062,0.1329,0.0614,0.0001,0.0,0.0023,0.0,1608.8,77.22,45.76,50.56
|
| 257 |
+
2026-02-20T15:45:00Z,2.7044,0.0,1.9534,0.5455,0.0092,0.1332,0.0594,0.0001,0.0,0.0036,0.0,1618.9,77.71,44.33,50.62
|
| 258 |
+
2026-02-20T16:00:00Z,2.3623,0.0,1.586,0.5623,0.0135,0.1351,0.0598,0.0003,0.0,0.0053,0.0,1627.2,78.11,46.53,50.65
|
| 259 |
+
2026-02-20T16:15:00Z,2.0647,0.0,1.2828,0.5549,0.0197,0.1355,0.0635,0.0006,0.0,0.0076,0.0,1633.9,78.43,43.93,50.65
|
| 260 |
+
2026-02-20T16:30:00Z,1.7901,0.0,0.9809,0.5724,0.0272,0.1358,0.062,0.0011,0.0,0.0106,0.0,1639.0,78.67,44.66,50.74
|
| 261 |
+
2026-02-20T16:45:00Z,1.4698,0.0,0.626,0.6011,0.0366,0.134,0.0556,0.0021,0.0,0.0143,0.0,1642.2,78.83,45.59,50.72
|
| 262 |
+
2026-02-20T17:00:00Z,1.1259,0.0,0.2403,0.6209,0.0493,0.1348,0.0586,0.0032,0.0,0.0189,0.0,1643.5,78.89,43.1,50.77
|
| 263 |
+
2026-02-20T17:15:00Z,0.803,0.0,-0.6732,0.6223,0.0631,0.1359,0.06,0.0052,0.566,0.0238,0.0,1640.0,78.72,43.72,50.77
|
| 264 |
+
2026-02-20T17:30:00Z,0.5024,0.0,-2.1073,0.6208,0.0793,0.1342,0.0633,0.0076,1.6733,0.0312,0.0,1629.0,78.19,42.45,50.69
|
| 265 |
+
2026-02-20T17:45:00Z,0.1751,0.0,-2.7761,0.6371,0.0961,0.1326,0.0633,0.0106,1.9726,0.0388,0.0,1614.6,77.5,44.75,50.77
|
| 266 |
+
2026-02-20T18:00:00Z,0.0,0.0,-3.3154,0.6437,0.113,0.1362,0.0618,0.0135,2.3025,0.0449,0.0,1597.3,76.67,0.0,50.54
|
| 267 |
+
2026-02-20T18:15:00Z,0.0,0.0,-3.9251,0.654,0.1315,0.1355,0.0616,0.0152,2.8758,0.0515,0.0,1576.8,75.69,0.0,50.44
|
| 268 |
+
2026-02-20T18:30:00Z,0.0,0.0,-3.8225,0.6455,0.1476,0.1341,0.062,0.0195,2.7571,0.0568,0.0,1556.9,74.73,0.0,50.55
|
| 269 |
+
2026-02-20T18:45:00Z,0.0,0.0,-4.4925,0.6534,0.1587,0.134,0.0618,0.0202,3.4013,0.0631,0.0,1533.5,73.61,0.0,50.48
|
| 270 |
+
2026-02-20T19:00:00Z,0.0,0.0,-4.6783,0.6243,0.1682,0.1342,0.0659,0.0198,3.6013,0.0647,0.0,1509.2,72.44,0.0,50.34
|
| 271 |
+
2026-02-20T19:15:00Z,0.0,0.0,-4.6644,0.6508,0.1728,0.1366,0.0626,0.0188,3.5581,0.0648,0.0,1484.9,71.27,0.0,50.32
|
| 272 |
+
2026-02-20T19:30:00Z,0.0,0.0,-5.1319,0.6616,0.175,0.136,0.0634,0.0161,4.0118,0.0681,0.0,1458.2,69.99,0.0,50.21
|
| 273 |
+
2026-02-20T19:45:00Z,0.0,0.0,-5.0621,0.6559,0.1663,0.1321,0.061,0.0133,3.9674,0.0662,0.0,1431.8,68.73,0.0,50.21
|
| 274 |
+
2026-02-20T20:00:00Z,0.0,0.0,-4.4078,0.6425,0.1609,0.1352,0.0663,0.0104,3.3324,0.0601,0.0,1408.8,67.62,0.0,50.02
|
| 275 |
+
2026-02-20T20:15:00Z,0.0,0.0,-3.924,0.6846,0.1478,0.1366,0.0618,0.0074,2.829,0.0567,0.0,1388.4,66.64,0.0,50.03
|
| 276 |
+
2026-02-20T20:30:00Z,0.0,0.0,-3.7895,0.6377,0.1304,0.1343,0.0593,0.0052,2.7712,0.0514,0.0,1368.7,65.7,0.0,49.94
|
| 277 |
+
2026-02-20T20:45:00Z,0.0,0.0,-3.1214,0.6444,0.1154,0.1347,0.0656,0.0035,2.1121,0.0457,0.0,1352.4,64.92,0.0,49.83
|
| 278 |
+
2026-02-20T21:00:00Z,0.0,0.0,-2.9659,0.6536,0.0983,0.1353,0.0586,0.0022,1.98,0.0379,0.0,1337.0,64.17,0.0,49.88
|
| 279 |
+
2026-02-20T21:15:00Z,0.0,0.0,-2.6475,0.612,0.0795,0.1352,0.0636,0.0012,1.7258,0.0302,0.0,1323.2,63.51,0.0,49.8
|
| 280 |
+
2026-02-20T21:30:00Z,0.0,0.0,-1.6224,0.6457,0.0635,0.1344,0.0659,0.0007,0.687,0.0252,0.0,1314.7,63.11,0.0,49.79
|
| 281 |
+
2026-02-20T21:45:00Z,0.0,0.0,-0.9102,0.6478,0.0492,0.1348,0.0587,0.0003,0.0,0.0193,0.0,1310.0,62.88,0.0,49.71
|
| 282 |
+
2026-02-20T22:00:00Z,0.0,0.0,-0.9122,0.6592,0.0379,0.137,0.0633,0.0001,0.0,0.0146,0.0,1305.2,62.65,0.0,49.73
|
| 283 |
+
2026-02-20T22:15:00Z,0.0,0.0,-0.8768,0.6481,0.0278,0.1339,0.0563,0.0001,0.0,0.0107,0.0,1300.7,62.43,0.0,49.63
|
| 284 |
+
2026-02-20T22:30:00Z,0.0,0.0,-0.8943,0.6652,0.0198,0.1352,0.0659,0.0,0.0,0.0082,0.0,1296.0,62.21,0.0,49.78
|
| 285 |
+
2026-02-20T22:45:00Z,0.0,0.0,-0.8661,0.6484,0.0138,0.1338,0.0646,0.0,0.0,0.0055,0.0,1291.5,61.99,0.0,49.71
|
| 286 |
+
2026-02-20T23:00:00Z,0.0,0.0,-0.8505,0.6462,0.0026,0.1347,0.0633,0.0,0.0,0.0037,0.0,1287.1,61.78,0.0,49.7
|
| 287 |
+
2026-02-20T23:15:00Z,0.0,0.0,-0.8635,0.663,0.002,0.1379,0.0582,0.0,0.0,0.0024,0.0,1282.6,61.56,0.0,49.74
|
| 288 |
+
2026-02-20T23:30:00Z,0.0,0.0,-0.8353,0.6345,0.002,0.1343,0.0629,0.0,0.0,0.0016,0.0,1278.2,61.35,0.0,49.72
|
| 289 |
+
2026-02-20T23:45:00Z,0.0,0.0,-0.8472,0.6518,0.002,0.1345,0.0579,0.0,0.0,0.001,0.0,1273.8,61.14,0.0,49.64
|
| 290 |
+
2026-02-21T00:00:00Z,0.0,0.0,-0.8642,0.6633,0.002,0.1359,0.0622,0.0,0.0,0.0008,0.0,1269.3,60.93,0.0,49.61
|
| 291 |
+
2026-02-21T00:15:00Z,0.0,0.0,-0.8534,0.6512,0.002,0.1375,0.062,0.0,0.0,0.0008,0.0,1264.8,60.71,0.0,49.55
|
| 292 |
+
2026-02-21T00:30:00Z,0.0,0.0,-0.8508,0.6498,0.002,0.1353,0.0628,0.0,0.0,0.0009,0.0,1260.4,60.5,0.0,49.55
|
| 293 |
+
2026-02-21T00:45:00Z,0.0,0.0,-0.8635,0.6618,0.002,0.1348,0.0641,0.0,0.0,0.0009,0.0,1255.9,60.28,0.0,49.67
|
| 294 |
+
2026-02-21T01:00:00Z,0.0,0.0,-0.8483,0.6526,0.002,0.1338,0.0591,0.0,0.0,0.0008,0.0,1251.5,60.07,0.0,49.63
|
| 295 |
+
2026-02-21T01:15:00Z,0.0,0.0,-0.8571,0.6602,0.002,0.1336,0.0605,0.0,0.0,0.0008,0.0,1247.0,59.86,0.0,49.62
|
| 296 |
+
2026-02-21T01:30:00Z,0.0,0.0,-0.8329,0.6365,0.002,0.1363,0.0572,0.0,0.0,0.0009,0.0,1242.7,59.65,0.0,49.63
|
| 297 |
+
2026-02-21T01:45:00Z,0.0,0.0,-0.8539,0.6557,0.002,0.135,0.0604,0.0,0.0,0.0008,0.0,1238.3,59.44,0.0,49.58
|
| 298 |
+
2026-02-21T02:00:00Z,0.0,0.0,-0.876,0.675,0.002,0.1337,0.0644,0.0,0.0,0.0008,0.0,1233.7,59.22,0.0,49.65
|
| 299 |
+
2026-02-21T02:15:00Z,0.0,0.0,-0.8775,0.6777,0.002,0.1367,0.0602,0.0,0.0,0.0008,0.0,1229.1,59.0,0.0,49.57
|
| 300 |
+
2026-02-21T02:30:00Z,0.0,0.0,-0.8532,0.6549,0.002,0.1336,0.0618,0.0,0.0,0.0008,0.0,1224.7,58.78,0.0,49.63
|
| 301 |
+
2026-02-21T02:45:00Z,0.0,0.0,-0.8447,0.6459,0.002,0.1358,0.0602,0.0,0.0,0.0008,0.0,1220.3,58.57,0.0,49.64
|
| 302 |
+
2026-02-21T03:00:00Z,0.0,0.0,-0.8623,0.6669,0.002,0.134,0.0584,0.0,0.0,0.0008,0.0,1215.8,58.36,0.0,49.49
|
| 303 |
+
2026-02-21T03:15:00Z,0.0,0.0,-0.8327,0.6372,0.002,0.133,0.0597,0.0,0.0,0.0008,0.0,1211.4,58.15,0.0,49.55
|
| 304 |
+
2026-02-21T03:30:00Z,0.0,0.0,-0.8351,0.6349,0.002,0.1347,0.0626,0.0,0.0,0.0008,0.0,1207.1,57.94,0.0,49.46
|
| 305 |
+
2026-02-21T03:45:00Z,0.0,0.0,-0.8471,0.6466,0.002,0.135,0.0626,0.0,0.0,0.0008,0.0,1202.7,57.73,0.0,49.46
|
| 306 |
+
2026-02-21T04:00:00Z,0.0,0.0,-0.8298,0.6248,0.002,0.133,0.0691,0.0001,0.0,0.0008,0.0,1198.4,57.52,0.0,49.49
|
| 307 |
+
2026-02-21T04:15:00Z,0.0,0.0,-0.8538,0.6495,0.002,0.1356,0.0655,0.0003,0.0,0.0009,0.0,1193.9,57.31,0.0,49.44
|
| 308 |
+
2026-02-21T04:30:00Z,0.0,0.0,-0.836,0.635,0.002,0.1344,0.0626,0.0005,0.0,0.0015,0.0,1189.6,57.1,0.0,49.37
|
| 309 |
+
2026-02-21T04:45:00Z,0.0,0.0,-0.8497,0.6475,0.002,0.1359,0.0605,0.001,0.0,0.0028,0.0,1185.1,56.89,0.0,49.48
|
| 310 |
+
2026-02-21T05:00:00Z,0.0,0.0,-0.8675,0.6638,0.002,0.1332,0.0619,0.0021,0.0,0.0046,0.0,1180.6,56.67,0.0,49.44
|
| 311 |
+
2026-02-21T05:15:00Z,0.0,0.0,-0.8368,0.6266,0.002,0.1353,0.0619,0.0032,0.0,0.0077,0.0,1176.3,56.46,0.0,49.43
|
| 312 |
+
2026-02-21T05:30:00Z,0.0,0.0,-0.865,0.6493,0.002,0.1348,0.0616,0.0054,0.0,0.012,0.0,1171.8,56.24,0.0,49.39
|
| 313 |
+
2026-02-21T05:45:00Z,0.0,0.0,-0.8553,0.626,0.002,0.1366,0.0643,0.0084,0.0,0.0181,0.0,1167.3,56.03,0.0,49.38
|
| 314 |
+
2026-02-21T06:00:00Z,0.1565,0.0,-1.2947,0.6652,0.0633,0.1338,0.0631,0.0137,0.4888,0.0233,0.0,1160.6,55.71,40.85,49.38
|
| 315 |
+
2026-02-21T06:15:00Z,0.4786,0.0,-2.4206,0.6616,0.0847,0.1342,0.0609,0.0182,1.9047,0.0348,0.0,1148.0,55.1,45.81,49.35
|
| 316 |
+
2026-02-21T06:30:00Z,0.7951,0.0,-2.563,0.6135,0.111,0.1327,0.0665,0.0238,2.366,0.0445,0.0,1134.6,54.46,44.79,49.37
|
| 317 |
+
2026-02-21T06:45:00Z,1.118,0.0,-3.0968,0.6071,0.1385,0.133,0.0658,0.0281,3.1879,0.0545,0.0,1118.5,53.69,46.45,49.25
|
| 318 |
+
2026-02-21T07:00:00Z,1.4519,0.0,-3.2223,0.5941,0.1675,0.1348,0.0628,0.0313,3.6227,0.061,0.0,1101.7,52.88,47.63,49.26
|
| 319 |
+
2026-02-21T07:15:00Z,1.7258,0.0,-3.3967,0.5625,0.1957,0.1345,0.0632,0.0353,4.057,0.0743,0.0,1084.0,52.03,45.58,49.14
|
| 320 |
+
2026-02-21T07:30:00Z,1.9835,0.0,-3.7702,0.5603,0.2064,0.1365,0.0613,0.0311,4.6792,0.0788,0.0,1064.4,51.09,43.9,49.16
|
| 321 |
+
2026-02-21T07:45:00Z,2.3779,0.0,-3.4049,0.5614,0.2183,0.1321,0.0609,0.0321,4.694,0.084,0.0,1046.6,50.24,45.02,48.96
|
| 322 |
+
2026-02-21T08:00:00Z,2.6321,0.0,-2.6799,0.5396,0.2172,0.1351,0.0609,0.0262,4.254,0.079,0.0,1032.7,49.57,43.43,49.04
|
| 323 |
+
2026-02-21T08:15:00Z,2.9712,0.0,-2.6439,0.5496,0.2081,0.1341,0.065,0.0235,4.5526,0.0823,0.0,1018.9,48.91,43.09,48.95
|
| 324 |
+
2026-02-21T08:30:00Z,3.1626,0.0,-1.8382,0.5238,0.1881,0.136,0.0597,0.017,4.0032,0.073,0.0,1009.3,48.45,45.51,48.83
|
| 325 |
+
2026-02-21T08:45:00Z,3.4024,0.0,-1.3029,0.5381,0.166,0.131,0.0657,0.014,3.7283,0.0623,0.0,1002.5,48.12,45.51,48.96
|
| 326 |
+
2026-02-21T09:00:00Z,3.5919,0.0,-0.2531,0.532,0.1394,0.1357,0.061,0.0087,2.9133,0.0549,0.0,1001.2,48.06,43.58,48.89
|
| 327 |
+
2026-02-21T09:15:00Z,3.8807,0.0,0.6672,0.5077,0.1122,0.1356,0.0594,0.0061,2.3485,0.0439,0.0,1004.7,48.23,45.3,48.88
|
| 328 |
+
2026-02-21T09:30:00Z,3.9537,0.0,1.376,0.4868,0.0894,0.1349,0.0605,0.0035,1.7678,0.0347,0.0,1011.9,48.57,44.65,48.89
|
| 329 |
+
2026-02-21T09:45:00Z,4.2681,0.0,2.8384,0.4934,0.0636,0.1364,0.0619,0.0021,0.6482,0.0241,0.0,1026.6,49.28,43.77,48.98
|
| 330 |
+
2026-02-21T10:00:00Z,4.423,0.0,3.6803,0.4813,0.0459,0.1357,0.0608,0.0011,0.0,0.0178,0.0,1045.8,50.2,41.99,49.03
|
| 331 |
+
2026-02-21T10:15:00Z,4.5404,0.0,3.8357,0.4684,0.0312,0.133,0.0591,0.0005,0.0,0.0123,0.0,1065.8,51.16,41.99,49.07
|
| 332 |
+
2026-02-21T10:30:00Z,4.6114,0.0,3.9176,0.4673,0.0206,0.136,0.0616,0.0003,0.0,0.008,0.0,1086.2,52.14,42.31,49.09
|
| 333 |
+
2026-02-21T10:45:00Z,4.9017,0.0,4.2245,0.4578,0.0124,0.1379,0.0641,0.0001,0.0,0.0048,0.0,1108.2,53.19,43.26,49.18
|
| 334 |
+
2026-02-21T11:00:00Z,4.7646,0.0,4.0894,0.4652,0.0075,0.1382,0.0614,0.0,0.0,0.0029,0.0,1129.5,54.22,41.83,49.19
|
| 335 |
+
2026-02-21T11:15:00Z,5.0468,0.0,4.4052,0.4398,0.0043,0.1354,0.0604,0.0,0.0,0.0017,0.0,1152.4,55.32,44.19,49.31
|
| 336 |
+
2026-02-21T11:30:00Z,5.0098,0.0,4.3405,0.4648,0.0025,0.1383,0.0629,0.0,0.0,0.001,0.0,1175.1,56.4,42.86,49.25
|
| 337 |
+
2026-02-21T11:45:00Z,5.0667,0.0,4.4202,0.447,0.0022,0.1364,0.0601,0.0,0.0,0.0008,0.0,1198.1,57.51,44.75,49.37
|
| 338 |
+
2026-02-21T12:00:00Z,4.9246,0.0,4.2746,0.4542,0.0022,0.1355,0.0572,0.0,0.0,0.0009,0.0,1220.3,58.58,42.34,49.4
|
| 339 |
+
2026-02-21T12:15:00Z,4.9728,0.0,4.325,0.4534,0.0022,0.1316,0.0598,0.0,0.0,0.0008,0.0,1242.9,59.66,42.73,49.54
|
| 340 |
+
2026-02-21T12:30:00Z,5.0541,0.0,4.4038,0.4479,0.0022,0.1374,0.062,0.0,0.0,0.0008,0.0,1265.8,60.76,43.7,49.59
|
| 341 |
+
2026-02-21T12:45:00Z,4.9293,0.0,4.28,0.4502,0.0022,0.1352,0.0609,0.0,0.0,0.0008,0.0,1288.1,61.83,44.42,49.68
|
| 342 |
+
2026-02-21T13:00:00Z,4.8403,0.0,4.1707,0.4687,0.0022,0.134,0.0639,0.0,0.0,0.0008,0.0,1309.8,62.87,43.79,49.66
|
| 343 |
+
2026-02-21T13:15:00Z,4.5028,0.0,3.8342,0.4683,0.0021,0.1361,0.0612,0.0,0.0,0.0008,0.0,1329.8,63.83,42.79,49.78
|
| 344 |
+
2026-02-21T13:30:00Z,4.541,0.0,3.8712,0.4728,0.0021,0.1355,0.0586,0.0,0.0,0.0008,0.0,1349.9,64.8,44.56,49.84
|
| 345 |
+
2026-02-21T13:45:00Z,4.3365,0.0,3.6621,0.4774,0.0021,0.134,0.06,0.0,0.0,0.0009,0.0,1369.0,65.71,42.5,50.0
|
| 346 |
+
2026-02-21T14:00:00Z,4.3479,0.0,3.6682,0.4781,0.0022,0.1373,0.0612,0.0,0.0,0.0008,0.0,1388.1,66.63,43.27,49.91
|
| 347 |
+
2026-02-21T14:15:00Z,4.0599,0.0,3.3784,0.4774,0.0021,0.1342,0.0669,0.0,0.0,0.0009,0.0,1405.7,67.47,45.54,50.08
|
| 348 |
+
2026-02-21T14:30:00Z,3.8371,0.0,3.1504,0.4817,0.0022,0.1342,0.0678,0.0,0.0,0.0008,0.0,1422.1,68.26,42.89,50.08
|
| 349 |
+
2026-02-21T14:45:00Z,3.7501,0.0,3.0443,0.506,0.0022,0.1343,0.0624,0.0,0.0,0.0008,0.0,1438.0,69.02,43.19,50.15
|
| 350 |
+
2026-02-21T15:00:00Z,3.448,0.0,2.7558,0.4977,0.0024,0.1328,0.0583,0.0,0.0,0.0009,0.0,1452.3,69.71,43.74,50.27
|
| 351 |
+
2026-02-21T15:15:00Z,3.2274,0.0,2.5153,0.5086,0.0039,0.1332,0.0649,0.0,0.0,0.0015,0.0,1465.4,70.34,43.96,50.3
|
| 352 |
+
2026-02-21T15:30:00Z,2.9415,0.0,2.2179,0.516,0.0061,0.1381,0.0609,0.0001,0.0,0.0024,0.0,1477.0,70.9,43.89,50.34
|
| 353 |
+
2026-02-21T15:45:00Z,2.6108,0.0,1.8443,0.5587,0.0095,0.1348,0.0596,0.0001,0.0,0.0037,0.0,1486.6,71.36,41.46,50.26
|
| 354 |
+
2026-02-21T16:00:00Z,2.3631,0.0,1.605,0.5455,0.0139,0.1354,0.0576,0.0003,0.0,0.0054,0.0,1495.0,71.76,44.77,50.25
|
| 355 |
+
2026-02-21T16:15:00Z,2.0619,0.0,1.2683,0.5709,0.0198,0.1345,0.0599,0.0006,0.0,0.0078,0.0,1501.6,72.07,43.03,50.31
|
| 356 |
+
2026-02-21T16:30:00Z,1.7514,0.0,0.9311,0.5817,0.027,0.1368,0.063,0.0012,0.0,0.0107,0.0,1506.4,72.31,44.66,50.32
|
| 357 |
+
2026-02-21T16:45:00Z,1.4486,0.0,0.6129,0.587,0.0372,0.1343,0.0605,0.0021,0.0,0.0146,0.0,1509.6,72.46,43.39,50.33
|
| 358 |
+
2026-02-21T17:00:00Z,1.1224,0.0,0.2489,0.6023,0.0484,0.1363,0.0644,0.0035,0.0,0.0186,0.0,1510.9,72.52,42.57,50.4
|
| 359 |
+
2026-02-21T17:15:00Z,0.8246,0.0,-0.7206,0.6559,0.0635,0.1336,0.0619,0.0053,0.5999,0.0253,0.0,1507.1,72.34,46.35,50.26
|
| 360 |
+
2026-02-21T17:30:00Z,0.5044,0.0,-2.1902,0.6219,0.0789,0.1368,0.0609,0.0075,1.7577,0.0309,0.0,1495.7,71.8,43.79,50.28
|
| 361 |
+
2026-02-21T17:45:00Z,0.1757,0.0,-2.8519,0.6434,0.0953,0.1347,0.0621,0.0114,2.0417,0.0391,0.0,1480.9,71.08,43.29,50.34
|
| 362 |
+
2026-02-21T18:00:00Z,0.0,0.0,-3.275,0.6615,0.1121,0.1341,0.0587,0.0133,2.2507,0.0445,0.0,1463.8,70.26,0.0,50.17
|
| 363 |
+
2026-02-21T18:15:00Z,0.0,0.0,-3.7737,0.6498,0.1301,0.1363,0.0608,0.0165,2.7284,0.0518,0.0,1444.2,69.32,0.0,50.25
|
| 364 |
+
2026-02-21T18:30:00Z,0.0,0.0,-4.1158,0.6401,0.1502,0.138,0.0604,0.0179,3.0487,0.0605,0.0,1422.7,68.29,0.0,50.18
|
| 365 |
+
2026-02-21T18:45:00Z,0.0,0.0,-4.5377,0.6735,0.158,0.1362,0.0627,0.0202,3.4238,0.0635,0.0,1399.1,67.16,0.0,50.12
|
| 366 |
+
2026-02-21T19:00:00Z,0.0,0.0,-4.5908,0.6546,0.1669,0.1346,0.0563,0.0204,3.4913,0.0667,0.0,1375.2,66.01,0.0,49.95
|
| 367 |
+
2026-02-21T19:15:00Z,0.0,0.0,-4.8523,0.6339,0.1749,0.1342,0.0641,0.0192,3.7624,0.0636,0.0,1349.9,64.8,0.0,49.8
|
| 368 |
+
2026-02-21T19:30:00Z,0.0,0.0,-5.0197,0.6582,0.1719,0.1346,0.0625,0.0172,3.9086,0.0668,0.0,1323.8,63.54,0.0,49.75
|
| 369 |
+
2026-02-21T19:45:00Z,0.0,0.0,-4.509,0.6547,0.1654,0.1355,0.0648,0.0145,3.4089,0.0651,0.0,1300.3,62.41,0.0,49.76
|
| 370 |
+
2026-02-21T20:00:00Z,0.0,0.0,-4.1981,0.6388,0.157,0.1375,0.0646,0.0112,3.1285,0.0607,0.0,1278.4,61.36,0.0,49.71
|
| 371 |
+
2026-02-21T20:15:00Z,0.0,0.0,-4.4103,0.6543,0.1459,0.1367,0.0626,0.0076,3.3453,0.058,0.0,1255.5,60.26,0.0,49.57
|
| 372 |
+
2026-02-21T20:30:00Z,0.0,0.0,-3.7535,0.639,0.1303,0.1339,0.0665,0.0052,2.729,0.0496,0.0,1235.9,59.32,0.0,49.57
|
| 373 |
+
2026-02-21T20:45:00Z,0.0,0.0,-3.5337,0.6465,0.1106,0.1368,0.062,0.0035,2.5294,0.0449,0.0,1217.5,58.44,0.0,49.56
|
| 374 |
+
2026-02-21T21:00:00Z,0.0,0.0,-2.8963,0.6304,0.0964,0.1376,0.0589,0.0021,1.9339,0.0369,0.0,1202.4,57.72,0.0,49.49
|
| 375 |
+
2026-02-21T21:15:00Z,0.0,0.0,-2.6789,0.6661,0.0801,0.1328,0.0654,0.0012,1.7013,0.032,0.0,1188.5,57.05,0.0,49.46
|
| 376 |
+
2026-02-21T21:30:00Z,0.0,0.0,-1.5566,0.6308,0.0623,0.1362,0.0622,0.0006,0.6396,0.0248,0.0,1180.4,56.66,0.0,49.4
|
| 377 |
+
2026-02-21T21:45:00Z,0.0,0.0,-0.9052,0.6374,0.0506,0.1354,0.0618,0.0004,0.0,0.0198,0.0,1175.6,56.43,0.0,49.39
|
| 378 |
+
2026-02-21T22:00:00Z,0.0,0.0,-0.9044,0.6532,0.0383,0.1349,0.063,0.0002,0.0,0.0149,0.0,1170.9,56.2,0.0,49.33
|
| 379 |
+
2026-02-21T22:15:00Z,0.0,0.0,-0.8977,0.6615,0.0278,0.1339,0.0635,0.0001,0.0,0.0108,0.0,1166.3,55.98,0.0,49.31
|
| 380 |
+
2026-02-21T22:30:00Z,0.0,0.0,-0.8381,0.6157,0.0203,0.1327,0.0618,0.0,0.0,0.0076,0.0,1161.9,55.77,0.0,49.28
|
| 381 |
+
2026-02-21T22:45:00Z,0.0,0.0,-0.8676,0.6547,0.0139,0.1337,0.06,0.0,0.0,0.0054,0.0,1157.4,55.55,0.0,49.24
|
| 382 |
+
2026-02-21T23:00:00Z,0.0,0.0,-0.8466,0.6434,0.0027,0.1356,0.0613,0.0,0.0,0.0037,0.0,1153.0,55.34,0.0,49.26
|
| 383 |
+
2026-02-21T23:15:00Z,0.0,0.0,-0.8674,0.6649,0.002,0.1352,0.0629,0.0,0.0,0.0024,0.0,1148.4,55.13,0.0,49.3
|
| 384 |
+
2026-02-21T23:30:00Z,0.0,0.0,-0.8438,0.6419,0.002,0.1339,0.0643,0.0,0.0,0.0016,0.0,1144.0,54.91,0.0,49.26
|
| 385 |
+
2026-02-21T23:45:00Z,0.0,0.0,-0.846,0.646,0.002,0.1354,0.0616,0.0,0.0,0.001,0.0,1139.6,54.7,0.0,49.34
|
output/power/1DAY.csv
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Time,Solar_Total_kWh,Shore_Total_kWh,Battery_Charged_kWh,Battery_Discharged_kWh,HVAC_Total_kWh,Lighting_Total_kWh,Devices_Total_kWh,Fridge_Total_kWh,WaterPump_Total_kWh,Cooking_Total_kWh,Inverter_Total_kWh,Unmetered_Total_kWh,Battery_Level_Ah,Battery_Level_Pct,Solar_Voltage_Avg_V,Battery_Voltage_Avg_V
|
| 2 |
+
2026-02-18T00:00:00Z,38.076662,0.0,24.32976,30.667985,14.135598,1.282062,3.24653,1.475973,0.131885,23.631153,0.511685,0.0,1534.6,73.66,21.94,50.71
|
| 3 |
+
2026-02-19T00:00:00Z,38.057265,0.0,24.323765,30.82545,14.151865,1.281073,3.250425,1.48185,0.133242,23.752057,0.508438,0.0,1399.2,67.16,21.98,50.32
|
| 4 |
+
2026-02-20T00:00:00Z,38.352155,0.0,24.442578,30.460525,14.116797,1.283768,3.23797,1.4857,0.132327,23.6025,0.51104,0.0,1273.8,61.14,21.82,49.95
|
| 5 |
+
2026-02-21T00:00:00Z,38.222703,0.0,24.515092,30.954448,14.08935,1.2869,3.241302,1.48587,0.135302,23.911335,0.512002,0.0,1139.6,54.7,21.92,49.58
|
output/power/1H.csv
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Time,Solar_Total_kWh,Shore_Total_kWh,Battery_Charged_kWh,Battery_Discharged_kWh,HVAC_Total_kWh,Lighting_Total_kWh,Devices_Total_kWh,Fridge_Total_kWh,WaterPump_Total_kWh,Cooking_Total_kWh,Inverter_Total_kWh,Unmetered_Total_kWh,Battery_Level_Ah,Battery_Level_Pct,Solar_Voltage_Avg_V,Battery_Voltage_Avg_V
|
| 2 |
+
2026-02-18T00:00:00Z,0.0,0.0,0.0,0.855355,0.654488,0.002,0.135705,0.062305,0.0,0.0,0.000857,0.0,1648.8,79.14,0.0,50.8
|
| 3 |
+
2026-02-18T01:00:00Z,0.0,0.0,0.0,0.846337,0.648863,0.002,0.13397,0.060677,0.0,0.0,0.000827,0.0,1631.2,78.3,0.0,50.7
|
| 4 |
+
2026-02-18T02:00:00Z,0.0,0.0,0.0,0.847543,0.64766,0.002,0.13584,0.061182,0.0,0.0,0.000862,0.0,1613.6,77.45,0.0,50.67
|
| 5 |
+
2026-02-18T03:00:00Z,0.0,0.0,0.0,0.869457,0.668278,0.002,0.135743,0.062607,1e-05,0.0,0.000818,0.0,1595.4,76.58,0.0,50.65
|
| 6 |
+
2026-02-18T04:00:00Z,0.0,0.0,0.0,0.851883,0.650238,0.002,0.13502,0.062605,0.000498,0.0,0.001522,0.0,1577.7,75.73,0.0,50.62
|
| 7 |
+
2026-02-18T05:00:00Z,0.0,0.0,0.0,0.863852,0.649357,0.002,0.134942,0.06225,0.005038,0.0,0.010265,0.0,1559.7,74.87,0.0,50.53
|
| 8 |
+
2026-02-18T06:00:00Z,0.644015,0.0,0.0,2.247272,0.621125,0.099772,0.136025,0.060473,0.019397,1.914483,0.040012,0.0,1512.9,72.62,43.13,50.41
|
| 9 |
+
2026-02-18T07:00:00Z,1.921423,0.0,0.0,3.338727,0.569808,0.19172,0.135102,0.062827,0.031782,4.19402,0.074892,0.0,1443.3,69.28,44.97,50.27
|
| 10 |
+
2026-02-18T08:00:00Z,3.014447,0.0,0.002447,2.209082,0.536385,0.195567,0.135612,0.060225,0.020018,4.19849,0.074785,0.0,1397.4,67.07,44.3,50.1
|
| 11 |
+
2026-02-18T09:00:00Z,3.891975,0.0,1.238545,0.084965,0.491053,0.10003,0.134425,0.06039,0.005128,1.908168,0.0392,0.0,1421.4,68.23,44.48,50.06
|
| 12 |
+
2026-02-18T10:00:00Z,4.569852,0.0,3.863942,0.0,0.472238,0.027295,0.134097,0.0612,0.0005,0.0,0.01058,0.0,1501.9,72.09,44.18,50.23
|
| 13 |
+
2026-02-18T11:00:00Z,4.98226,0.0,4.323893,0.0,0.457055,0.004103,0.135117,0.060467,1.3e-05,0.0,0.001612,0.0,1592.0,76.41,43.72,50.42
|
| 14 |
+
2026-02-18T12:00:00Z,4.885727,0.0,4.225135,0.0,0.46023,0.002155,0.135265,0.06209,0.0,0.0,0.000852,0.0,1680.0,80.64,43.71,50.74
|
| 15 |
+
2026-02-18T13:00:00Z,4.580578,0.0,3.918417,0.0,0.463922,0.002153,0.135343,0.059905,0.0,0.0,0.000838,0.0,1761.6,84.56,43.32,50.98
|
| 16 |
+
2026-02-18T14:00:00Z,4.003418,0.0,3.307328,0.0,0.495052,0.002147,0.136,0.062057,0.0,0.0,0.000835,0.0,1830.5,87.87,43.12,51.18
|
| 17 |
+
2026-02-18T15:00:00Z,3.006577,0.0,2.266167,0.0,0.538208,0.0054,0.134763,0.059893,5.8e-05,0.0,0.002087,0.0,1877.7,90.13,43.49,51.32
|
| 18 |
+
2026-02-18T16:00:00Z,1.91499,0.0,1.110767,0.0,0.573375,0.024422,0.1343,0.0615,0.00103,0.0,0.009597,0.0,1900.9,91.24,43.91,51.45
|
| 19 |
+
2026-02-18T17:00:00Z,0.6614,0.0,0.07312,1.371418,0.619123,0.07158,0.135953,0.063783,0.006788,1.035183,0.027287,0.0,1873.8,89.94,44.24,51.47
|
| 20 |
+
2026-02-18T18:00:00Z,0.0,0.0,0.0,4.018715,0.651103,0.136768,0.135622,0.060758,0.016807,2.964232,0.053425,0.0,1790.1,85.93,0.0,51.28
|
| 21 |
+
2026-02-18T19:00:00Z,0.0,0.0,0.0,4.594473,0.648175,0.168807,0.136447,0.061685,0.016943,3.495293,0.067123,0.0,1694.4,81.33,0.0,51.03
|
| 22 |
+
2026-02-18T20:00:00Z,0.0,0.0,0.0,3.908307,0.657942,0.138337,0.134782,0.063028,0.006775,2.853917,0.053527,0.0,1613.0,77.42,0.0,50.77
|
| 23 |
+
2026-02-18T21:00:00Z,0.0,0.0,0.0,2.02254,0.655618,0.072667,0.135553,0.062408,0.001038,1.067367,0.027888,0.0,1570.8,75.4,0.0,50.59
|
| 24 |
+
2026-02-18T22:00:00Z,0.0,0.0,0.0,0.876237,0.646107,0.024997,0.135578,0.059633,6e-05,0.0,0.009862,0.0,1552.6,74.52,0.0,50.49
|
| 25 |
+
2026-02-18T23:00:00Z,0.0,0.0,0.0,0.861823,0.660193,0.002143,0.135327,0.062025,0.0,0.0,0.002135,0.0,1534.6,73.66,0.0,50.41
|
| 26 |
+
2026-02-19T00:00:00Z,0.0,0.0,0.0,0.864395,0.660658,0.002,0.136717,0.064188,0.0,0.0,0.000832,0.0,1516.6,72.8,0.0,50.4
|
| 27 |
+
2026-02-19T01:00:00Z,0.0,0.0,0.0,0.844488,0.644677,0.002,0.13536,0.061595,0.0,0.0,0.000857,0.0,1499.0,71.95,0.0,50.31
|
| 28 |
+
2026-02-19T02:00:00Z,0.0,0.0,0.0,0.859117,0.657887,0.002,0.135262,0.063127,0.0,0.0,0.000842,0.0,1481.1,71.09,0.0,50.3
|
| 29 |
+
2026-02-19T03:00:00Z,0.0,0.0,0.0,0.84273,0.641955,0.002,0.133912,0.064013,1.2e-05,0.0,0.000838,0.0,1463.6,70.25,0.0,50.25
|
| 30 |
+
2026-02-19T04:00:00Z,0.0,0.0,0.0,0.8661,0.662362,0.002,0.136693,0.063057,0.00047,0.0,0.001518,0.0,1445.5,69.38,0.0,50.21
|
| 31 |
+
2026-02-19T05:00:00Z,0.0,0.0,0.0,0.8679,0.654865,0.002,0.135802,0.060467,0.004782,0.0,0.009985,0.0,1427.4,68.52,0.0,50.13
|
| 32 |
+
2026-02-19T06:00:00Z,0.629232,0.0,0.0,2.35239,0.621932,0.099787,0.135895,0.062042,0.020212,2.002137,0.039618,0.0,1378.4,66.16,43.12,50.03
|
| 33 |
+
2026-02-19T07:00:00Z,1.914067,0.0,0.0,3.315613,0.581233,0.19227,0.135597,0.06184,0.032523,4.151463,0.074753,0.0,1309.4,62.85,45.11,49.86
|
| 34 |
+
2026-02-19T08:00:00Z,3.022743,0.0,0.00425,2.040217,0.539148,0.190627,0.134532,0.059632,0.020327,4.039117,0.075328,0.0,1266.9,60.81,43.66,49.65
|
| 35 |
+
2026-02-19T09:00:00Z,3.9425,0.0,1.275183,0.156533,0.496765,0.101917,0.136633,0.06138,0.004968,1.983247,0.03894,0.0,1290.2,61.93,44.44,49.64
|
| 36 |
+
2026-02-19T10:00:00Z,4.626238,0.0,3.91343,0.0,0.47581,0.027178,0.135627,0.062745,0.00052,0.0,0.010928,0.0,1371.8,65.85,44.68,49.85
|
| 37 |
+
2026-02-19T11:00:00Z,4.837432,0.0,4.179718,0.0,0.457663,0.0041,0.135393,0.058982,7e-06,0.0,0.001568,0.0,1458.9,70.02,43.63,50.14
|
| 38 |
+
2026-02-19T12:00:00Z,4.977692,0.0,4.32778,0.0,0.450518,0.00216,0.135128,0.061255,0.0,0.0,0.00085,0.0,1549.0,74.35,43.09,50.31
|
| 39 |
+
2026-02-19T13:00:00Z,4.58805,0.0,3.917898,0.0,0.470335,0.002163,0.134855,0.061952,0.0,0.0,0.000847,0.0,1630.6,78.27,44.02,50.57
|
| 40 |
+
2026-02-19T14:00:00Z,3.928615,0.0,3.23061,0.0,0.498535,0.002132,0.134463,0.06205,0.0,0.0,0.000825,0.0,1697.9,81.5,43.53,50.8
|
| 41 |
+
2026-02-19T15:00:00Z,3.029595,0.0,2.301332,0.0,0.526113,0.005455,0.134892,0.05958,6e-05,0.0,0.002163,0.0,1745.9,83.8,44.08,50.94
|
| 42 |
+
2026-02-19T16:00:00Z,1.902025,0.0,1.100757,0.0,0.569732,0.024558,0.136747,0.059728,0.001015,0.0,0.009488,0.0,1768.8,84.9,44.33,51.05
|
| 43 |
+
2026-02-19T17:00:00Z,0.659077,0.0,0.072807,1.429737,0.620997,0.072333,0.136285,0.061272,0.006543,1.091105,0.027472,0.0,1740.5,83.55,43.74,51.1
|
| 44 |
+
2026-02-19T18:00:00Z,0.0,0.0,0.0,3.963292,0.654547,0.136685,0.13514,0.061032,0.017163,2.905835,0.05289,0.0,1658.0,79.58,0.0,50.84
|
| 45 |
+
2026-02-19T19:00:00Z,0.0,0.0,0.0,4.704807,0.660122,0.171132,0.13634,0.062585,0.01673,3.591748,0.06615,0.0,1560.0,74.88,0.0,50.62
|
| 46 |
+
2026-02-19T20:00:00Z,0.0,0.0,0.0,3.95338,0.645982,0.136253,0.134583,0.061975,0.006807,2.91577,0.05201,0.0,1477.6,70.92,0.0,50.39
|
| 47 |
+
2026-02-19T21:00:00Z,0.0,0.0,0.0,2.016312,0.643958,0.073155,0.134787,0.063883,0.001048,1.071635,0.027845,0.0,1435.6,68.91,0.0,50.21
|
| 48 |
+
2026-02-19T22:00:00Z,0.0,0.0,0.0,0.892467,0.660283,0.025013,0.13467,0.062688,5.5e-05,0.0,0.009757,0.0,1417.0,68.02,0.0,50.12
|
| 49 |
+
2026-02-19T23:00:00Z,0.0,0.0,0.0,0.855973,0.655788,0.002155,0.135113,0.060783,0.0,0.0,0.002133,0.0,1399.2,67.16,0.0,50.04
|
| 50 |
+
2026-02-20T00:00:00Z,0.0,0.0,0.0,0.853588,0.650425,0.002,0.136305,0.064018,0.0,0.0,0.00084,0.0,1381.4,66.31,0.0,50.01
|
| 51 |
+
2026-02-20T01:00:00Z,0.0,0.0,0.0,0.844687,0.645078,0.002,0.13485,0.061925,0.0,0.0,0.000833,0.0,1363.8,65.46,0.0,49.94
|
| 52 |
+
2026-02-20T02:00:00Z,0.0,0.0,0.0,0.847528,0.648953,0.002,0.135095,0.060635,0.0,0.0,0.000845,0.0,1346.1,64.61,0.0,49.93
|
| 53 |
+
2026-02-20T03:00:00Z,0.0,0.0,0.0,0.842303,0.641663,0.002,0.13423,0.063553,7e-06,0.0,0.00085,0.0,1328.6,63.77,0.0,49.87
|
| 54 |
+
2026-02-20T04:00:00Z,0.0,0.0,0.0,0.84551,0.644558,0.002,0.135057,0.061847,0.00049,0.0,0.001558,0.0,1311.0,62.93,0.0,49.78
|
| 55 |
+
2026-02-20T05:00:00Z,0.0,0.0,0.0,0.864638,0.652483,0.002,0.134847,0.059918,0.00505,0.0,0.01034,0.0,1293.0,62.06,0.0,49.73
|
| 56 |
+
2026-02-20T06:00:00Z,0.646785,0.0,0.0,2.22802,0.636592,0.099833,0.133628,0.062762,0.020003,1.88368,0.038307,0.0,1246.5,59.83,43.02,49.63
|
| 57 |
+
2026-02-20T07:00:00Z,1.887662,0.0,0.0,3.282692,0.581712,0.190385,0.134572,0.06027,0.031532,4.0965,0.075383,0.0,1178.1,56.55,43.93,49.46
|
| 58 |
+
2026-02-20T08:00:00Z,3.067253,0.0,0.000733,1.934322,0.527063,0.19349,0.135628,0.062145,0.020165,3.987303,0.075047,0.0,1137.9,54.62,43.73,49.34
|
| 59 |
+
2026-02-20T09:00:00Z,3.92396,0.0,1.14406,0.168363,0.501317,0.102022,0.134357,0.062758,0.00499,2.103833,0.038987,0.0,1158.2,55.59,44.68,49.24
|
| 60 |
+
2026-02-20T10:00:00Z,4.634325,0.0,3.923728,0.0,0.474307,0.027343,0.13518,0.062642,0.000502,0.0,0.010623,0.0,1239.9,59.52,43.01,49.47
|
| 61 |
+
2026-02-20T11:00:00Z,4.995682,0.0,4.332482,0.0,0.460548,0.004068,0.135145,0.06183,8e-06,0.0,0.0016,0.0,1330.2,63.85,43.57,49.75
|
| 62 |
+
2026-02-20T12:00:00Z,4.914305,0.0,4.249965,0.0,0.464017,0.002178,0.135838,0.061463,0.0,0.0,0.000843,0.0,1418.7,68.1,43.44,49.99
|
| 63 |
+
2026-02-20T13:00:00Z,4.65703,0.0,3.9773,0.0,0.480003,0.002152,0.134765,0.06197,0.0,0.0,0.00084,0.0,1501.6,72.08,42.54,50.15
|
| 64 |
+
2026-02-20T14:00:00Z,3.958903,0.0,3.264372,0.0,0.4935,0.002168,0.135105,0.062937,0.0,0.0,0.000822,0.0,1569.6,75.34,42.88,50.44
|
| 65 |
+
2026-02-20T15:00:00Z,3.092937,0.0,2.367902,0.0,0.5232,0.005437,0.133787,0.06046,5.5e-05,0.0,0.002097,0.0,1618.9,77.71,44.24,50.61
|
| 66 |
+
2026-02-20T16:00:00Z,1.921722,0.0,1.11893,0.0,0.572655,0.024262,0.135103,0.060243,0.001048,0.0,0.00948,0.0,1642.2,78.83,45.18,50.69
|
| 67 |
+
2026-02-20T17:00:00Z,0.651592,0.0,0.063107,1.392203,0.625277,0.071943,0.134373,0.061287,0.006663,1.052973,0.028172,0.0,1614.6,77.5,43.5,50.75
|
| 68 |
+
2026-02-20T18:00:00Z,0.0,0.0,0.0,3.888878,0.649148,0.13769,0.134925,0.061803,0.017087,2.834162,0.054063,0.0,1533.5,73.61,0.0,50.5
|
| 69 |
+
2026-02-20T19:00:00Z,0.0,0.0,0.0,4.884177,0.648145,0.170572,0.134718,0.063197,0.016967,3.784643,0.065935,0.0,1431.8,68.73,0.0,50.27
|
| 70 |
+
2026-02-20T20:00:00Z,0.0,0.0,0.0,3.810663,0.652282,0.13865,0.135207,0.063238,0.0066,2.761195,0.053492,0.0,1352.4,64.92,0.0,49.95
|
| 71 |
+
2026-02-20T21:00:00Z,0.0,0.0,0.0,2.036488,0.639782,0.072628,0.134928,0.061698,0.001103,1.09821,0.028138,0.0,1310.0,62.88,0.0,49.79
|
| 72 |
+
2026-02-20T22:00:00Z,0.0,0.0,0.0,0.887358,0.655225,0.0248,0.134983,0.062527,5.7e-05,0.0,0.009767,0.0,1291.5,61.99,0.0,49.71
|
| 73 |
+
2026-02-20T23:00:00Z,0.0,0.0,0.0,0.849105,0.648863,0.002147,0.135343,0.060573,0.0,0.0,0.002178,0.0,1273.8,61.14,0.0,49.7
|
| 74 |
+
2026-02-21T00:00:00Z,0.0,0.0,0.0,0.85798,0.656547,0.002,0.135848,0.062755,0.0,0.0,0.00083,0.0,1255.9,60.28,0.0,49.6
|
| 75 |
+
2026-02-21T01:00:00Z,0.0,0.0,0.0,0.848032,0.651248,0.002,0.134653,0.05931,0.0,0.0,0.00082,0.0,1238.3,59.44,0.0,49.62
|
| 76 |
+
2026-02-21T02:00:00Z,0.0,0.0,0.0,0.862865,0.663402,0.002,0.134965,0.061663,0.0,0.0,0.000835,0.0,1220.3,58.57,0.0,49.62
|
| 77 |
+
2026-02-21T03:00:00Z,0.0,0.0,0.0,0.844287,0.646392,0.002,0.134202,0.06085,1e-05,0.0,0.000833,0.0,1202.7,57.73,0.0,49.49
|
| 78 |
+
2026-02-21T04:00:00Z,0.0,0.0,0.0,0.842325,0.639238,0.002,0.134703,0.064408,0.000467,0.0,0.001508,0.0,1185.1,56.89,0.0,49.44
|
| 79 |
+
2026-02-21T05:00:00Z,0.0,0.0,0.0,0.856137,0.64139,0.002,0.13496,0.062413,0.00478,0.0,0.010593,0.0,1167.3,56.03,0.0,49.41
|
| 80 |
+
2026-02-21T06:00:00Z,0.637045,0.0,0.0,2.343768,0.636853,0.099385,0.133423,0.064053,0.020943,1.986862,0.039293,0.0,1118.5,53.69,44.48,49.34
|
| 81 |
+
2026-02-21T07:00:00Z,1.884788,0.0,0.0,3.448528,0.569553,0.196968,0.134495,0.062078,0.032462,4.263247,0.074513,0.0,1046.6,50.24,45.53,49.13
|
| 82 |
+
2026-02-21T08:00:00Z,3.042072,0.0,0.000938,2.117172,0.537758,0.194842,0.134042,0.062825,0.020188,4.134515,0.074135,0.0,1002.5,48.12,44.39,48.95
|
| 83 |
+
2026-02-21T09:00:00Z,3.923607,0.0,1.266867,0.109737,0.50496,0.101155,0.135678,0.06069,0.005122,1.91945,0.039422,0.0,1026.6,49.28,44.32,48.91
|
| 84 |
+
2026-02-21T10:00:00Z,4.619105,0.0,3.914548,0.0,0.468698,0.027537,0.135643,0.061432,0.000512,0.0,0.010735,0.0,1108.2,53.19,42.39,49.09
|
| 85 |
+
2026-02-21T11:00:00Z,4.971983,0.0,4.313828,0.0,0.45418,0.004102,0.137067,0.061218,1e-05,0.0,0.001578,0.0,1198.1,57.51,43.41,49.28
|
| 86 |
+
2026-02-21T12:00:00Z,4.970208,0.0,4.320863,0.0,0.451418,0.002177,0.134937,0.05997,0.0,0.0,0.000843,0.0,1288.1,61.83,43.3,49.55
|
| 87 |
+
2026-02-21T13:00:00Z,4.555165,0.0,3.88455,0.0,0.471777,0.002148,0.134893,0.06095,0.0,0.0,0.000847,0.0,1369.0,65.71,43.41,49.82
|
| 88 |
+
2026-02-21T14:00:00Z,3.99873,0.0,3.310335,0.0,0.485812,0.00219,0.135007,0.064567,0.0,0.0,0.00082,0.0,1438.0,69.02,43.73,50.05
|
| 89 |
+
2026-02-21T15:00:00Z,3.056947,0.0,2.333318,0.0,0.520255,0.005497,0.134738,0.060937,5.7e-05,0.0,0.002145,0.0,1486.6,71.36,43.26,50.29
|
| 90 |
+
2026-02-21T16:00:00Z,1.906257,0.0,1.104308,0.0,0.571275,0.02447,0.135245,0.060233,0.001072,0.0,0.009653,0.0,1509.6,72.46,43.96,50.3
|
| 91 |
+
2026-02-21T17:00:00Z,0.656797,0.0,0.065535,1.443993,0.630855,0.071535,0.135348,0.06232,0.006928,1.099808,0.02846,0.0,1480.9,71.08,44.0,50.32
|
| 92 |
+
2026-02-21T18:00:00Z,0.0,0.0,0.0,3.925553,0.656213,0.137565,0.136172,0.060648,0.016975,2.862907,0.055073,0.0,1399.1,67.16,0.0,50.18
|
| 93 |
+
2026-02-21T19:00:00Z,0.0,0.0,0.0,4.742977,0.650355,0.169778,0.134737,0.061953,0.01781,3.642805,0.065538,0.0,1300.3,62.41,0.0,49.82
|
| 94 |
+
2026-02-21T20:00:00Z,0.0,0.0,0.0,3.973915,0.644658,0.135947,0.136205,0.063938,0.006855,2.933032,0.05328,0.0,1217.5,58.44,0.0,49.6
|
| 95 |
+
2026-02-21T21:00:00Z,0.0,0.0,0.0,2.009253,0.641173,0.072343,0.13551,0.062078,0.001045,1.06871,0.028393,0.0,1175.6,56.43,0.0,49.44
|
| 96 |
+
2026-02-21T22:00:00Z,0.0,0.0,0.0,0.876968,0.64627,0.025095,0.13378,0.062075,6.7e-05,0.0,0.009682,0.0,1157.4,55.55,0.0,49.29
|
| 97 |
+
2026-02-21T23:00:00Z,0.0,0.0,0.0,0.850958,0.649068,0.002167,0.13505,0.062503,0.0,0.0,0.00217,0.0,1139.6,54.7,0.0,49.29
|
output/power/1MIN.csv
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
output/power/1SEC.csv
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
output/stability_index.csv
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
output/water/15MIN.csv
ADDED
|
@@ -0,0 +1,385 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Time,Inlet_Flow_Lpm,Pump_Flow_Lpm,Shower_Flow_Lpm,Kitchen_Flow_Lpm,Toilet_Flow_Lpm,Unmetered_Flow_Lpm,FreshTank_Level_L,GreyTank_Level_L,BlackTank_Level_L
|
| 2 |
+
2026-02-18T00:00:00Z,0.0,0.0,0.0,0.0,0.0,0.0,359.61,0.0,0.0
|
| 3 |
+
2026-02-18T00:15:00Z,0.0,0.0,0.0,0.0,0.0,0.0,359.61,0.0,0.0
|
| 4 |
+
2026-02-18T00:30:00Z,0.0,0.0,0.0,0.0,0.0,0.0,359.61,0.0,0.0
|
| 5 |
+
2026-02-18T00:45:00Z,0.0,0.0,0.0,0.0,0.0,0.0,359.61,0.0,0.0
|
| 6 |
+
2026-02-18T01:00:00Z,0.0,0.0,0.0,0.0,0.0,0.0,359.61,0.0,0.0
|
| 7 |
+
2026-02-18T01:15:00Z,0.0,0.0,0.0,0.0,0.0,0.0,359.61,0.0,0.0
|
| 8 |
+
2026-02-18T01:30:00Z,0.0,0.0,0.0,0.0,0.0,0.0,359.61,0.0,0.0
|
| 9 |
+
2026-02-18T01:45:00Z,0.0,0.0,0.0,0.0,0.0,0.0,359.61,0.0,0.0
|
| 10 |
+
2026-02-18T02:00:00Z,0.0,0.0,0.0,0.0,0.0,0.0,359.61,0.0,0.0
|
| 11 |
+
2026-02-18T02:15:00Z,0.0,0.0,0.0,0.0,0.0,0.0,359.61,0.0,0.0
|
| 12 |
+
2026-02-18T02:30:00Z,0.0,0.0,0.0,0.0,0.0,0.0,359.61,0.0,0.0
|
| 13 |
+
2026-02-18T02:45:00Z,0.0,0.0,0.0,0.0,0.0,0.0,359.61,0.0,0.0
|
| 14 |
+
2026-02-18T03:00:00Z,0.0,0.0,0.0,0.0,0.0,0.0,359.61,0.0,0.0
|
| 15 |
+
2026-02-18T03:15:00Z,0.0,0.0,0.0,0.0,0.0,0.0,359.61,0.0,0.0
|
| 16 |
+
2026-02-18T03:30:00Z,0.0,0.0002,0.0001,0.0,0.0,0.0,359.61,0.0,0.0
|
| 17 |
+
2026-02-18T03:45:00Z,0.0,0.0004,0.0003,0.0001,0.0,0.0,359.6,0.01,0.0
|
| 18 |
+
2026-02-18T04:00:00Z,0.0,0.0011,0.0006,0.0003,0.0001,0.0,359.59,0.02,0.0
|
| 19 |
+
2026-02-18T04:15:00Z,0.0,0.0023,0.0014,0.0007,0.0003,0.0,359.55,0.05,0.01
|
| 20 |
+
2026-02-18T04:30:00Z,0.0,0.0049,0.0029,0.0015,0.0005,0.0,359.48,0.11,0.01
|
| 21 |
+
2026-02-18T04:45:00Z,0.0,0.01,0.0063,0.0027,0.001,0.0,359.33,0.23,0.03
|
| 22 |
+
2026-02-18T05:00:00Z,0.0,0.0186,0.0118,0.0049,0.0018,0.0,359.05,0.45,0.06
|
| 23 |
+
2026-02-18T05:15:00Z,0.0,0.0334,0.0208,0.0092,0.0034,0.0,358.55,0.86,0.11
|
| 24 |
+
2026-02-18T05:30:00Z,0.0,0.0541,0.0336,0.0151,0.0055,0.0,357.74,1.52,0.19
|
| 25 |
+
2026-02-18T05:45:00Z,0.0,0.0835,0.051,0.0233,0.0091,0.0,356.49,2.52,0.33
|
| 26 |
+
2026-02-18T06:00:00Z,0.0,0.1249,0.0785,0.0337,0.0127,0.0,354.61,4.03,0.52
|
| 27 |
+
2026-02-18T06:15:00Z,0.0,0.1652,0.1047,0.045,0.0155,0.0,352.14,6.05,0.75
|
| 28 |
+
2026-02-18T06:30:00Z,0.0,0.2114,0.1302,0.0579,0.0233,0.0,348.97,8.59,1.1
|
| 29 |
+
2026-02-18T06:45:00Z,0.0,0.264,0.1659,0.0712,0.0269,0.0,345.01,11.79,1.5
|
| 30 |
+
2026-02-18T07:00:00Z,0.7036,0.2976,0.1908,0.079,0.0278,0.0,351.1,15.44,1.92
|
| 31 |
+
2026-02-18T07:15:00Z,0.0,0.3098,0.1931,0.0839,0.0327,0.0,346.45,19.18,2.41
|
| 32 |
+
2026-02-18T07:30:00Z,0.0,0.3232,0.1997,0.0894,0.0342,0.0,341.6,23.08,2.93
|
| 33 |
+
2026-02-18T07:45:00Z,0.0,0.298,0.1828,0.0854,0.0298,0.0,337.13,26.7,3.37
|
| 34 |
+
2026-02-18T08:00:00Z,0.0,0.2616,0.1636,0.0703,0.0278,0.0,333.21,29.85,3.79
|
| 35 |
+
2026-02-18T08:15:00Z,0.0,0.2262,0.139,0.0621,0.0251,0.0,329.81,32.57,4.17
|
| 36 |
+
2026-02-18T08:30:00Z,0.0,0.1731,0.1083,0.0478,0.0171,0.0,327.22,34.67,4.42
|
| 37 |
+
2026-02-18T08:45:00Z,0.0,0.1243,0.0763,0.0347,0.0134,0.0,325.35,36.17,4.62
|
| 38 |
+
2026-02-18T09:00:00Z,0.0,0.0836,0.0495,0.0251,0.009,0.0,324.1,37.18,4.76
|
| 39 |
+
2026-02-18T09:15:00Z,0.0,0.0548,0.0337,0.0151,0.006,0.0,323.28,37.84,4.85
|
| 40 |
+
2026-02-18T09:30:00Z,0.0,0.0322,0.0191,0.0095,0.0037,0.0,322.79,38.22,4.9
|
| 41 |
+
2026-02-18T09:45:00Z,0.0,0.0199,0.0121,0.0057,0.0021,0.0,322.49,38.47,4.93
|
| 42 |
+
2026-02-18T10:00:00Z,0.0,0.0103,0.0062,0.0029,0.0011,0.0,322.34,38.59,4.95
|
| 43 |
+
2026-02-18T10:15:00Z,0.0,0.0052,0.0032,0.0014,0.0005,0.0,322.26,38.65,4.96
|
| 44 |
+
2026-02-18T10:30:00Z,0.0,0.0024,0.0015,0.0007,0.0002,0.0,322.23,38.68,4.96
|
| 45 |
+
2026-02-18T10:45:00Z,0.0,0.0011,0.0007,0.0003,0.0001,0.0,322.21,38.7,4.96
|
| 46 |
+
2026-02-18T11:00:00Z,0.0,0.0005,0.0003,0.0001,0.0,0.0,322.2,38.7,4.96
|
| 47 |
+
2026-02-18T11:15:00Z,0.0,0.0002,0.0001,0.0001,0.0,0.0,322.2,38.7,4.96
|
| 48 |
+
2026-02-18T11:30:00Z,0.0,0.0,0.0,0.0,0.0,0.0,322.2,38.7,4.96
|
| 49 |
+
2026-02-18T11:45:00Z,0.0,0.0,0.0,0.0,0.0,0.0,322.2,38.7,4.96
|
| 50 |
+
2026-02-18T12:00:00Z,0.0,0.0,0.0,0.0,0.0,0.0,322.2,38.7,4.96
|
| 51 |
+
2026-02-18T12:15:00Z,0.0,0.0,0.0,0.0,0.0,0.0,322.2,38.7,4.96
|
| 52 |
+
2026-02-18T12:30:00Z,0.0,0.0,0.0,0.0,0.0,0.0,322.2,38.7,4.96
|
| 53 |
+
2026-02-18T12:45:00Z,0.0,0.0,0.0,0.0,0.0,0.0,322.2,38.7,4.96
|
| 54 |
+
2026-02-18T13:00:00Z,0.0,0.0,0.0,0.0,0.0,0.0,322.2,38.7,4.96
|
| 55 |
+
2026-02-18T13:15:00Z,0.0,0.0,0.0,0.0,0.0,0.0,322.2,38.7,4.96
|
| 56 |
+
2026-02-18T13:30:00Z,0.0,0.0,0.0,0.0,0.0,0.0,322.2,38.7,4.96
|
| 57 |
+
2026-02-18T13:45:00Z,0.0,0.0,0.0,0.0,0.0,0.0,322.2,38.7,4.96
|
| 58 |
+
2026-02-18T14:00:00Z,0.0,0.0,0.0,0.0,0.0,0.0,322.2,38.7,4.96
|
| 59 |
+
2026-02-18T14:15:00Z,0.0,0.0,0.0,0.0,0.0,0.0,322.2,38.7,4.96
|
| 60 |
+
2026-02-18T14:30:00Z,0.0,0.0,0.0,0.0,0.0,0.0,322.2,38.7,4.96
|
| 61 |
+
2026-02-18T14:45:00Z,0.0,0.0,0.0,0.0,0.0,0.0,322.2,38.7,4.96
|
| 62 |
+
2026-02-18T15:00:00Z,0.0,0.0001,0.0001,0.0,0.0,0.0,322.2,38.71,4.96
|
| 63 |
+
2026-02-18T15:15:00Z,0.0,0.0003,0.0002,0.0001,0.0,0.0,322.19,38.71,4.96
|
| 64 |
+
2026-02-18T15:30:00Z,0.0,0.0006,0.0004,0.0002,0.0001,0.0,322.18,38.72,4.97
|
| 65 |
+
2026-02-18T15:45:00Z,0.0,0.0014,0.0009,0.0004,0.0001,0.0,322.16,38.73,4.97
|
| 66 |
+
2026-02-18T16:00:00Z,0.0,0.0029,0.0017,0.0009,0.0003,0.0,322.12,38.77,4.97
|
| 67 |
+
2026-02-18T16:15:00Z,0.0,0.0061,0.0038,0.0016,0.0006,0.0,322.03,38.84,4.98
|
| 68 |
+
2026-02-18T16:30:00Z,0.0,0.0118,0.0074,0.0031,0.0013,0.0,321.85,38.98,5.0
|
| 69 |
+
2026-02-18T16:45:00Z,0.0,0.0209,0.0131,0.0058,0.002,0.0,321.54,39.24,5.03
|
| 70 |
+
2026-02-18T17:00:00Z,0.0,0.0335,0.0208,0.0093,0.0033,0.0,321.03,39.65,5.08
|
| 71 |
+
2026-02-18T17:15:00Z,0.0,0.0507,0.0307,0.0145,0.0054,0.0,320.27,40.26,5.16
|
| 72 |
+
2026-02-18T17:30:00Z,0.0,0.0757,0.0456,0.0216,0.0085,0.0,319.14,41.16,5.29
|
| 73 |
+
2026-02-18T17:45:00Z,0.0,0.1028,0.0648,0.0276,0.0105,0.0,317.6,42.41,5.45
|
| 74 |
+
2026-02-18T18:00:00Z,0.0,0.1288,0.0802,0.0351,0.0135,0.0,315.66,43.97,5.65
|
| 75 |
+
2026-02-18T18:15:00Z,0.0,0.1554,0.0971,0.0424,0.0159,0.0,313.33,45.85,5.89
|
| 76 |
+
2026-02-18T18:30:00Z,0.0,0.1693,0.1037,0.0474,0.0181,0.0,310.79,47.89,6.16
|
| 77 |
+
2026-02-18T18:45:00Z,0.0,0.1916,0.1161,0.0554,0.0201,0.0,307.92,50.21,6.46
|
| 78 |
+
2026-02-18T19:00:00Z,0.0,0.1895,0.1197,0.0509,0.0189,0.0,305.08,52.51,6.75
|
| 79 |
+
2026-02-18T19:15:00Z,0.0,0.18,0.1126,0.0501,0.0173,0.0,302.38,54.71,7.0
|
| 80 |
+
2026-02-18T19:30:00Z,0.0,0.1553,0.0969,0.0431,0.0153,0.0,300.05,56.6,7.23
|
| 81 |
+
2026-02-18T19:45:00Z,0.0,0.1326,0.083,0.0361,0.0136,0.0,298.06,58.2,7.44
|
| 82 |
+
2026-02-18T20:00:00Z,0.0,0.1029,0.0636,0.0288,0.0105,0.0,296.52,59.45,7.6
|
| 83 |
+
2026-02-18T20:15:00Z,0.0,0.0719,0.0436,0.0212,0.0072,0.0,295.44,60.32,7.7
|
| 84 |
+
2026-02-18T20:30:00Z,0.0,0.0499,0.0307,0.0138,0.0055,0.0,294.69,60.92,7.78
|
| 85 |
+
2026-02-18T20:45:00Z,0.0,0.0329,0.0199,0.0091,0.0039,0.0,294.2,61.32,7.84
|
| 86 |
+
2026-02-18T21:00:00Z,0.0,0.0207,0.0127,0.0058,0.0023,0.0,293.88,61.57,7.88
|
| 87 |
+
2026-02-18T21:15:00Z,0.0,0.0117,0.0073,0.0032,0.0012,0.0,293.71,61.71,7.9
|
| 88 |
+
2026-02-18T21:30:00Z,0.0,0.0062,0.0039,0.0017,0.0007,0.0,293.62,61.78,7.91
|
| 89 |
+
2026-02-18T21:45:00Z,0.0,0.0032,0.002,0.0009,0.0003,0.0,293.57,61.82,7.91
|
| 90 |
+
2026-02-18T22:00:00Z,0.0,0.0015,0.0009,0.0004,0.0002,0.0,293.55,61.84,7.91
|
| 91 |
+
2026-02-18T22:15:00Z,0.0,0.0007,0.0004,0.0002,0.0001,0.0,293.54,61.85,7.91
|
| 92 |
+
2026-02-18T22:30:00Z,0.0,0.0003,0.0002,0.0001,0.0,0.0,293.53,61.85,7.91
|
| 93 |
+
2026-02-18T22:45:00Z,0.0,0.0001,0.0001,0.0,0.0,0.0,293.53,61.85,7.91
|
| 94 |
+
2026-02-18T23:00:00Z,0.0,0.0,0.0,0.0,0.0,0.0,293.53,61.85,7.91
|
| 95 |
+
2026-02-18T23:15:00Z,0.0,0.0,0.0,0.0,0.0,0.0,293.53,61.85,7.91
|
| 96 |
+
2026-02-18T23:30:00Z,0.0,0.0,0.0,0.0,0.0,0.0,293.53,61.85,7.91
|
| 97 |
+
2026-02-18T23:45:00Z,0.0,0.0,0.0,0.0,0.0,0.0,293.53,61.85,7.91
|
| 98 |
+
2026-02-19T00:00:00Z,0.0,0.0,0.0,0.0,0.0,0.0,293.53,61.85,7.91
|
| 99 |
+
2026-02-19T00:15:00Z,0.0,0.0,0.0,0.0,0.0,0.0,293.53,61.85,7.91
|
| 100 |
+
2026-02-19T00:30:00Z,0.0,0.0,0.0,0.0,0.0,0.0,293.53,61.85,7.91
|
| 101 |
+
2026-02-19T00:45:00Z,0.0,0.0,0.0,0.0,0.0,0.0,293.53,61.85,7.91
|
| 102 |
+
2026-02-19T01:00:00Z,0.0,0.0,0.0,0.0,0.0,0.0,293.53,61.85,7.91
|
| 103 |
+
2026-02-19T01:15:00Z,0.0,0.0,0.0,0.0,0.0,0.0,293.53,61.85,7.91
|
| 104 |
+
2026-02-19T01:30:00Z,0.0,0.0,0.0,0.0,0.0,0.0,293.53,61.85,7.91
|
| 105 |
+
2026-02-19T01:45:00Z,0.0,0.0,0.0,0.0,0.0,0.0,293.53,61.85,7.91
|
| 106 |
+
2026-02-19T02:00:00Z,0.0,0.0,0.0,0.0,0.0,0.0,293.53,61.85,7.91
|
| 107 |
+
2026-02-19T02:15:00Z,0.0,0.0,0.0,0.0,0.0,0.0,293.53,61.85,7.91
|
| 108 |
+
2026-02-19T02:30:00Z,0.0,0.0,0.0,0.0,0.0,0.0,293.53,61.85,7.91
|
| 109 |
+
2026-02-19T02:45:00Z,0.0,0.0,0.0,0.0,0.0,0.0,293.53,61.85,7.91
|
| 110 |
+
2026-02-19T03:00:00Z,0.0,0.0,0.0,0.0,0.0,0.0,293.53,61.85,7.91
|
| 111 |
+
2026-02-19T03:15:00Z,0.0,0.0,0.0,0.0,0.0,0.0,293.53,61.85,7.91
|
| 112 |
+
2026-02-19T03:30:00Z,0.0,0.0001,0.0001,0.0,0.0,0.0,293.53,61.85,7.91
|
| 113 |
+
2026-02-19T03:45:00Z,0.0,0.0004,0.0003,0.0001,0.0,0.0,293.52,61.86,7.91
|
| 114 |
+
2026-02-19T04:00:00Z,0.0,0.0011,0.0007,0.0003,0.0001,0.0,293.5,61.87,7.92
|
| 115 |
+
2026-02-19T04:15:00Z,0.0,0.0023,0.0014,0.0007,0.0003,0.0,293.47,61.9,7.92
|
| 116 |
+
2026-02-19T04:30:00Z,0.0,0.0049,0.003,0.0014,0.0005,0.0,293.4,61.96,7.93
|
| 117 |
+
2026-02-19T04:45:00Z,0.0,0.01,0.0061,0.0029,0.001,0.0,293.24,62.08,7.94
|
| 118 |
+
2026-02-19T05:00:00Z,0.0,0.0196,0.012,0.0054,0.0022,0.0,292.95,62.32,7.98
|
| 119 |
+
2026-02-19T05:15:00Z,0.0,0.0337,0.0213,0.0087,0.0037,0.0,292.45,62.72,8.03
|
| 120 |
+
2026-02-19T05:30:00Z,0.0,0.0541,0.034,0.0143,0.0057,0.0,291.63,63.37,8.12
|
| 121 |
+
2026-02-19T05:45:00Z,0.0,0.083,0.051,0.023,0.009,0.0,290.39,64.37,8.25
|
| 122 |
+
2026-02-19T06:00:00Z,0.0,0.125,0.0776,0.0346,0.0128,0.0,288.51,65.89,8.44
|
| 123 |
+
2026-02-19T06:15:00Z,0.0,0.1663,0.1009,0.0465,0.0189,0.0,286.02,67.88,8.73
|
| 124 |
+
2026-02-19T06:30:00Z,0.0,0.2081,0.1278,0.0604,0.0199,0.0,282.9,70.42,9.03
|
| 125 |
+
2026-02-19T06:45:00Z,0.0,0.2552,0.1556,0.0713,0.0284,0.0,279.07,73.48,9.45
|
| 126 |
+
2026-02-19T07:00:00Z,0.0,0.2886,0.1739,0.084,0.0306,0.0,274.74,76.97,9.91
|
| 127 |
+
2026-02-19T07:15:00Z,0.0,0.3242,0.201,0.0894,0.0337,0.0,269.88,80.89,10.42
|
| 128 |
+
2026-02-19T07:30:00Z,0.0,0.3137,0.1969,0.0831,0.0337,0.0,265.17,84.67,10.92
|
| 129 |
+
2026-02-19T07:45:00Z,0.0,0.3008,0.1885,0.0844,0.0279,0.0,260.66,88.35,11.34
|
| 130 |
+
2026-02-19T08:00:00Z,0.0,0.2675,0.1677,0.0722,0.0276,0.0,256.65,91.59,11.75
|
| 131 |
+
2026-02-19T08:15:00Z,0.0,0.2219,0.1383,0.0601,0.0235,0.0,253.32,94.27,12.11
|
| 132 |
+
2026-02-19T08:30:00Z,0.0,0.1725,0.1057,0.0478,0.0191,0.0,250.73,96.34,12.39
|
| 133 |
+
2026-02-19T08:45:00Z,0.0,0.128,0.0794,0.0364,0.0122,0.0,248.81,97.9,12.58
|
| 134 |
+
2026-02-19T09:00:00Z,0.0,0.0916,0.0578,0.0244,0.0094,0.0,247.44,99.01,12.72
|
| 135 |
+
2026-02-19T09:15:00Z,0.0,0.0582,0.0368,0.016,0.0054,0.0,246.57,99.72,12.8
|
| 136 |
+
2026-02-19T09:30:00Z,0.0,0.0344,0.0216,0.0094,0.0034,0.0,246.05,100.14,12.85
|
| 137 |
+
2026-02-19T09:45:00Z,0.0,0.0189,0.0116,0.0054,0.0019,0.0,245.76,100.37,12.88
|
| 138 |
+
2026-02-19T10:00:00Z,0.0,0.0109,0.0067,0.003,0.0012,0.0,245.6,100.5,12.9
|
| 139 |
+
2026-02-19T10:15:00Z,0.0,0.0049,0.0029,0.0014,0.0006,0.0,245.53,100.56,12.9
|
| 140 |
+
2026-02-19T10:30:00Z,0.0,0.0026,0.0016,0.0007,0.0003,0.0,245.49,100.59,12.91
|
| 141 |
+
2026-02-19T10:45:00Z,0.0,0.0012,0.0007,0.0003,0.0001,0.0,245.47,100.61,12.91
|
| 142 |
+
2026-02-19T11:00:00Z,0.0,0.0005,0.0003,0.0001,0.0,0.0,245.46,100.61,12.91
|
| 143 |
+
2026-02-19T11:15:00Z,0.0,0.0002,0.0001,0.0001,0.0,0.0,245.46,100.62,12.91
|
| 144 |
+
2026-02-19T11:30:00Z,0.0,0.0,0.0,0.0,0.0,0.0,245.46,100.62,12.91
|
| 145 |
+
2026-02-19T11:45:00Z,0.0,0.0,0.0,0.0,0.0,0.0,245.46,100.62,12.91
|
| 146 |
+
2026-02-19T12:00:00Z,0.0,0.0,0.0,0.0,0.0,0.0,245.46,100.62,12.91
|
| 147 |
+
2026-02-19T12:15:00Z,0.0,0.0,0.0,0.0,0.0,0.0,245.46,100.62,12.91
|
| 148 |
+
2026-02-19T12:30:00Z,0.0,0.0,0.0,0.0,0.0,0.0,245.46,100.62,12.91
|
| 149 |
+
2026-02-19T12:45:00Z,0.0,0.0,0.0,0.0,0.0,0.0,245.46,100.62,12.91
|
| 150 |
+
2026-02-19T13:00:00Z,0.0,0.0,0.0,0.0,0.0,0.0,245.46,100.62,12.91
|
| 151 |
+
2026-02-19T13:15:00Z,0.0,0.0,0.0,0.0,0.0,0.0,245.46,100.62,12.91
|
| 152 |
+
2026-02-19T13:30:00Z,0.0,0.0,0.0,0.0,0.0,0.0,245.46,100.62,12.91
|
| 153 |
+
2026-02-19T13:45:00Z,0.0,0.0,0.0,0.0,0.0,0.0,245.46,100.62,12.91
|
| 154 |
+
2026-02-19T14:00:00Z,0.0,0.0,0.0,0.0,0.0,0.0,245.46,100.62,12.91
|
| 155 |
+
2026-02-19T14:15:00Z,0.0,0.0,0.0,0.0,0.0,0.0,245.46,100.62,12.91
|
| 156 |
+
2026-02-19T14:30:00Z,0.0,0.0,0.0,0.0,0.0,0.0,245.46,100.62,12.91
|
| 157 |
+
2026-02-19T14:45:00Z,0.0,0.0,0.0,0.0,0.0,0.0,245.46,100.62,12.91
|
| 158 |
+
2026-02-19T15:00:00Z,0.0,0.0001,0.0001,0.0,0.0,0.0,245.46,100.62,12.91
|
| 159 |
+
2026-02-19T15:15:00Z,0.0,0.0003,0.0002,0.0001,0.0,0.0,245.46,100.62,12.91
|
| 160 |
+
2026-02-19T15:30:00Z,0.0,0.0006,0.0004,0.0002,0.0001,0.0,245.45,100.63,12.91
|
| 161 |
+
2026-02-19T15:45:00Z,0.0,0.0014,0.0009,0.0004,0.0001,0.0,245.43,100.64,12.91
|
| 162 |
+
2026-02-19T16:00:00Z,0.0,0.0031,0.002,0.0009,0.0003,0.0,245.38,100.68,12.92
|
| 163 |
+
2026-02-19T16:15:00Z,0.0,0.0061,0.0037,0.0017,0.0007,0.0,245.29,100.76,12.93
|
| 164 |
+
2026-02-19T16:30:00Z,0.0,0.0111,0.0067,0.0031,0.0013,0.0,245.12,100.89,12.95
|
| 165 |
+
2026-02-19T16:45:00Z,0.0,0.0209,0.0131,0.0056,0.0022,0.0,244.81,101.14,12.98
|
| 166 |
+
2026-02-19T17:00:00Z,0.0,0.034,0.0219,0.0085,0.0036,0.0,244.3,101.55,13.04
|
| 167 |
+
2026-02-19T17:15:00Z,0.0,0.0511,0.032,0.0139,0.0052,0.0,243.53,102.17,13.11
|
| 168 |
+
2026-02-19T17:30:00Z,0.0,0.0758,0.0476,0.0208,0.0073,0.0,242.4,103.1,13.22
|
| 169 |
+
2026-02-19T17:45:00Z,0.0,0.104,0.0632,0.0296,0.0112,0.0,240.84,104.35,13.39
|
| 170 |
+
2026-02-19T18:00:00Z,0.0,0.1283,0.0793,0.035,0.014,0.0,238.91,105.89,13.6
|
| 171 |
+
2026-02-19T18:15:00Z,0.0,0.1546,0.095,0.0429,0.0167,0.0,236.59,107.75,13.85
|
| 172 |
+
2026-02-19T18:30:00Z,0.0,0.1725,0.107,0.0475,0.0179,0.0,234.0,109.84,14.12
|
| 173 |
+
2026-02-19T18:45:00Z,0.0,0.1847,0.1114,0.054,0.0192,0.0,231.24,112.07,14.41
|
| 174 |
+
2026-02-19T19:00:00Z,0.0,0.1837,0.1121,0.0531,0.0186,0.0,228.48,114.3,14.69
|
| 175 |
+
2026-02-19T19:15:00Z,0.0,0.1781,0.1097,0.0513,0.0171,0.0,225.81,116.48,14.94
|
| 176 |
+
2026-02-19T19:30:00Z,0.0,0.161,0.101,0.0443,0.0157,0.0,223.39,118.44,15.18
|
| 177 |
+
2026-02-19T19:45:00Z,0.0,0.1267,0.0763,0.0367,0.0137,0.0,221.49,119.96,15.38
|
| 178 |
+
2026-02-19T20:00:00Z,0.0,0.0994,0.0604,0.0286,0.0105,0.0,220.0,121.16,15.54
|
| 179 |
+
2026-02-19T20:15:00Z,0.0,0.0752,0.0469,0.0212,0.0071,0.0,218.87,122.08,15.65
|
| 180 |
+
2026-02-19T20:30:00Z,0.0,0.0528,0.0335,0.014,0.0053,0.0,218.08,122.72,15.73
|
| 181 |
+
2026-02-19T20:45:00Z,0.0,0.0339,0.021,0.0097,0.0032,0.0,217.57,123.14,15.78
|
| 182 |
+
2026-02-19T21:00:00Z,0.0,0.0204,0.0129,0.0054,0.0021,0.0,217.27,123.39,15.81
|
| 183 |
+
2026-02-19T21:15:00Z,0.0,0.012,0.0075,0.0032,0.0014,0.0,217.09,123.53,15.83
|
| 184 |
+
2026-02-19T21:30:00Z,0.0,0.0064,0.004,0.0018,0.0006,0.0,216.99,123.61,15.84
|
| 185 |
+
2026-02-19T21:45:00Z,0.0,0.0032,0.002,0.0009,0.0003,0.0,216.94,123.65,15.84
|
| 186 |
+
2026-02-19T22:00:00Z,0.0,0.0015,0.0009,0.0004,0.0002,0.0,216.92,123.66,15.84
|
| 187 |
+
2026-02-19T22:15:00Z,0.0,0.0007,0.0005,0.0002,0.0001,0.0,216.91,123.67,15.84
|
| 188 |
+
2026-02-19T22:30:00Z,0.0,0.0003,0.0002,0.0001,0.0,0.0,216.91,123.68,15.84
|
| 189 |
+
2026-02-19T22:45:00Z,0.0,0.0001,0.0001,0.0,0.0,0.0,216.9,123.68,15.84
|
| 190 |
+
2026-02-19T23:00:00Z,0.0,0.0,0.0,0.0,0.0,0.0,216.9,123.68,15.84
|
| 191 |
+
2026-02-19T23:15:00Z,0.0,0.0,0.0,0.0,0.0,0.0,216.9,123.68,15.84
|
| 192 |
+
2026-02-19T23:30:00Z,0.0,0.0,0.0,0.0,0.0,0.0,216.9,123.68,15.84
|
| 193 |
+
2026-02-19T23:45:00Z,0.0,0.0,0.0,0.0,0.0,0.0,216.9,123.68,15.84
|
| 194 |
+
2026-02-20T00:00:00Z,0.0,0.0,0.0,0.0,0.0,0.0,216.9,123.68,15.84
|
| 195 |
+
2026-02-20T00:15:00Z,0.0,0.0,0.0,0.0,0.0,0.0,216.9,123.68,15.84
|
| 196 |
+
2026-02-20T00:30:00Z,0.0,0.0,0.0,0.0,0.0,0.0,216.9,123.68,15.84
|
| 197 |
+
2026-02-20T00:45:00Z,0.0,0.0,0.0,0.0,0.0,0.0,216.9,123.68,15.84
|
| 198 |
+
2026-02-20T01:00:00Z,0.0,0.0,0.0,0.0,0.0,0.0,216.9,123.68,15.84
|
| 199 |
+
2026-02-20T01:15:00Z,0.0,0.0,0.0,0.0,0.0,0.0,216.9,123.68,15.84
|
| 200 |
+
2026-02-20T01:30:00Z,0.0,0.0,0.0,0.0,0.0,0.0,216.9,123.68,15.84
|
| 201 |
+
2026-02-20T01:45:00Z,0.0,0.0,0.0,0.0,0.0,0.0,216.9,123.68,15.84
|
| 202 |
+
2026-02-20T02:00:00Z,0.0,0.0,0.0,0.0,0.0,0.0,216.9,123.68,15.84
|
| 203 |
+
2026-02-20T02:15:00Z,0.0,0.0,0.0,0.0,0.0,0.0,216.9,123.68,15.84
|
| 204 |
+
2026-02-20T02:30:00Z,0.0,0.0,0.0,0.0,0.0,0.0,216.9,123.68,15.84
|
| 205 |
+
2026-02-20T02:45:00Z,0.0,0.0,0.0,0.0,0.0,0.0,216.9,123.68,15.84
|
| 206 |
+
2026-02-20T03:00:00Z,0.0,0.0,0.0,0.0,0.0,0.0,216.9,123.68,15.84
|
| 207 |
+
2026-02-20T03:15:00Z,0.0,0.0,0.0,0.0,0.0,0.0,216.9,123.68,15.84
|
| 208 |
+
2026-02-20T03:30:00Z,0.0,0.0001,0.0001,0.0,0.0,0.0,216.9,123.68,15.84
|
| 209 |
+
2026-02-20T03:45:00Z,0.0,0.0004,0.0003,0.0001,0.0001,0.0,216.9,123.69,15.84
|
| 210 |
+
2026-02-20T04:00:00Z,0.0,0.0011,0.0007,0.0003,0.0001,0.0,216.88,123.7,15.85
|
| 211 |
+
2026-02-20T04:15:00Z,0.0,0.0025,0.0015,0.0007,0.0002,0.0,216.84,123.73,15.85
|
| 212 |
+
2026-02-20T04:30:00Z,0.0,0.005,0.0031,0.0015,0.0005,0.0,216.77,123.79,15.86
|
| 213 |
+
2026-02-20T04:45:00Z,0.0,0.0103,0.0064,0.0028,0.001,0.0,216.61,123.91,15.87
|
| 214 |
+
2026-02-20T05:00:00Z,0.0,0.0185,0.0114,0.0052,0.0019,0.0,216.33,124.14,15.9
|
| 215 |
+
2026-02-20T05:15:00Z,0.0,0.0321,0.0196,0.0088,0.0036,0.0,215.85,124.52,15.96
|
| 216 |
+
2026-02-20T05:30:00Z,0.0,0.0556,0.0349,0.0151,0.0056,0.0,215.02,125.2,16.04
|
| 217 |
+
2026-02-20T05:45:00Z,0.0,0.0811,0.0491,0.0236,0.0084,0.0,213.8,126.18,16.17
|
| 218 |
+
2026-02-20T06:00:00Z,0.0,0.1257,0.0775,0.0351,0.0131,0.0,211.92,127.7,16.36
|
| 219 |
+
2026-02-20T06:15:00Z,0.0,0.1731,0.109,0.0475,0.0166,0.0,209.32,129.81,16.61
|
| 220 |
+
2026-02-20T06:30:00Z,0.0,0.2185,0.1343,0.0618,0.0224,0.0,206.04,132.46,16.95
|
| 221 |
+
2026-02-20T06:45:00Z,0.0,0.2576,0.1594,0.0728,0.0254,0.0,202.18,135.59,17.33
|
| 222 |
+
2026-02-20T07:00:00Z,0.0,0.2939,0.1792,0.0824,0.0323,0.0,197.77,139.13,17.81
|
| 223 |
+
2026-02-20T07:15:00Z,0.0,0.3158,0.1931,0.0899,0.0327,0.0,193.03,142.95,18.3
|
| 224 |
+
2026-02-20T07:30:00Z,0.0,0.3055,0.1858,0.089,0.0307,0.0,188.45,146.66,18.76
|
| 225 |
+
2026-02-20T07:45:00Z,0.0,0.2903,0.175,0.0824,0.033,0.0,184.1,150.13,19.26
|
| 226 |
+
2026-02-20T08:00:00Z,0.0,0.2624,0.1608,0.0746,0.027,0.0,180.16,153.31,19.66
|
| 227 |
+
2026-02-20T08:15:00Z,0.0,0.2148,0.1332,0.0592,0.0224,0.0,176.94,155.91,20.0
|
| 228 |
+
2026-02-20T08:30:00Z,0.0,0.1793,0.1131,0.0479,0.0182,0.0,174.25,158.08,20.27
|
| 229 |
+
2026-02-20T08:45:00Z,0.0,0.1276,0.077,0.0362,0.0144,0.0,172.34,159.61,20.49
|
| 230 |
+
2026-02-20T09:00:00Z,0.0,0.085,0.0507,0.0243,0.01,0.0,171.06,160.62,20.64
|
| 231 |
+
2026-02-20T09:15:00Z,0.0,0.056,0.0349,0.0156,0.0055,0.0,170.22,161.3,20.72
|
| 232 |
+
2026-02-20T09:30:00Z,0.0,0.0331,0.02,0.0095,0.0037,0.0,169.72,161.7,20.78
|
| 233 |
+
2026-02-20T09:45:00Z,0.0,0.0201,0.0127,0.0054,0.0021,0.0,169.42,161.94,20.81
|
| 234 |
+
2026-02-20T10:00:00Z,0.0,0.0104,0.0065,0.0029,0.001,0.0,169.27,162.07,20.82
|
| 235 |
+
2026-02-20T10:15:00Z,0.0,0.0051,0.0031,0.0015,0.0006,0.0,169.19,162.13,20.83
|
| 236 |
+
2026-02-20T10:30:00Z,0.0,0.0026,0.0016,0.0007,0.0002,0.0,169.15,162.16,20.83
|
| 237 |
+
2026-02-20T10:45:00Z,0.0,0.0011,0.0007,0.0003,0.0001,0.0,169.13,162.18,20.84
|
| 238 |
+
2026-02-20T11:00:00Z,0.0,0.0005,0.0003,0.0001,0.0,0.0,169.13,162.18,20.84
|
| 239 |
+
2026-02-20T11:15:00Z,0.0,0.0002,0.0001,0.0001,0.0,0.0,169.12,162.19,20.84
|
| 240 |
+
2026-02-20T11:30:00Z,0.0,0.0,0.0,0.0,0.0,0.0,169.12,162.19,20.84
|
| 241 |
+
2026-02-20T11:45:00Z,0.0,0.0,0.0,0.0,0.0,0.0,169.12,162.19,20.84
|
| 242 |
+
2026-02-20T12:00:00Z,0.0,0.0,0.0,0.0,0.0,0.0,169.12,162.19,20.84
|
| 243 |
+
2026-02-20T12:15:00Z,0.0,0.0,0.0,0.0,0.0,0.0,169.12,162.19,20.84
|
| 244 |
+
2026-02-20T12:30:00Z,0.0,0.0,0.0,0.0,0.0,0.0,169.12,162.19,20.84
|
| 245 |
+
2026-02-20T12:45:00Z,0.0,0.0,0.0,0.0,0.0,0.0,169.12,162.19,20.84
|
| 246 |
+
2026-02-20T13:00:00Z,0.0,0.0,0.0,0.0,0.0,0.0,169.12,162.19,20.84
|
| 247 |
+
2026-02-20T13:15:00Z,0.0,0.0,0.0,0.0,0.0,0.0,169.12,162.19,20.84
|
| 248 |
+
2026-02-20T13:30:00Z,0.0,0.0,0.0,0.0,0.0,0.0,169.12,162.19,20.84
|
| 249 |
+
2026-02-20T13:45:00Z,0.0,0.0,0.0,0.0,0.0,0.0,169.12,162.19,20.84
|
| 250 |
+
2026-02-20T14:00:00Z,0.0,0.0,0.0,0.0,0.0,0.0,169.12,162.19,20.84
|
| 251 |
+
2026-02-20T14:15:00Z,0.0,0.0,0.0,0.0,0.0,0.0,169.12,162.19,20.84
|
| 252 |
+
2026-02-20T14:30:00Z,0.0,0.0,0.0,0.0,0.0,0.0,169.12,162.19,20.84
|
| 253 |
+
2026-02-20T14:45:00Z,0.0,0.0,0.0,0.0,0.0,0.0,169.12,162.19,20.84
|
| 254 |
+
2026-02-20T15:00:00Z,0.0,0.0001,0.0001,0.0,0.0,0.0,169.12,162.19,20.84
|
| 255 |
+
2026-02-20T15:15:00Z,0.0,0.0003,0.0002,0.0001,0.0,0.0,169.12,162.19,20.84
|
| 256 |
+
2026-02-20T15:30:00Z,0.0,0.0006,0.0004,0.0002,0.0001,0.0,169.11,162.2,20.84
|
| 257 |
+
2026-02-20T15:45:00Z,0.0,0.0014,0.0009,0.0004,0.0001,0.0,169.09,162.22,20.84
|
| 258 |
+
2026-02-20T16:00:00Z,0.0,0.0031,0.0019,0.0009,0.0003,0.0,169.04,162.25,20.85
|
| 259 |
+
2026-02-20T16:15:00Z,0.0,0.0059,0.0034,0.0018,0.0007,0.0,168.95,162.32,20.86
|
| 260 |
+
2026-02-20T16:30:00Z,0.0,0.0113,0.0068,0.0032,0.0013,0.0,168.78,162.46,20.87
|
| 261 |
+
2026-02-20T16:45:00Z,0.0,0.0198,0.0124,0.0054,0.002,0.0,168.49,162.7,20.9
|
| 262 |
+
2026-02-20T17:00:00Z,0.0,0.0342,0.022,0.0091,0.0032,0.0,167.97,163.12,20.95
|
| 263 |
+
2026-02-20T17:15:00Z,0.0,0.0492,0.0301,0.0144,0.0047,0.0,167.24,163.72,21.02
|
| 264 |
+
2026-02-20T17:30:00Z,0.0,0.0723,0.0455,0.0201,0.0067,0.0,166.15,164.61,21.12
|
| 265 |
+
2026-02-20T17:45:00Z,0.0,0.1025,0.065,0.0278,0.0097,0.0,164.61,165.86,21.27
|
| 266 |
+
2026-02-20T18:00:00Z,0.0,0.1273,0.0787,0.035,0.0136,0.0,162.7,167.39,21.47
|
| 267 |
+
2026-02-20T18:15:00Z,0.0,0.1558,0.0976,0.0427,0.0155,0.0,160.37,169.29,21.7
|
| 268 |
+
2026-02-20T18:30:00Z,0.0,0.1792,0.1102,0.0498,0.0193,0.0,157.68,171.45,21.99
|
| 269 |
+
2026-02-20T18:45:00Z,0.0,0.1809,0.1105,0.0506,0.0197,0.0,154.96,173.62,22.29
|
| 270 |
+
2026-02-20T19:00:00Z,0.0,0.1942,0.1192,0.055,0.02,0.0,152.05,175.97,22.59
|
| 271 |
+
2026-02-20T19:15:00Z,0.0,0.1768,0.1075,0.0503,0.0189,0.0,149.4,178.11,22.87
|
| 272 |
+
2026-02-20T19:30:00Z,0.0,0.1534,0.0905,0.0456,0.0173,0.0,147.1,179.94,23.13
|
| 273 |
+
2026-02-20T19:45:00Z,0.0,0.134,0.0844,0.0353,0.0143,0.0,145.09,181.56,23.35
|
| 274 |
+
2026-02-20T20:00:00Z,0.0,0.1043,0.0665,0.0272,0.0105,0.0,143.52,182.82,23.5
|
| 275 |
+
2026-02-20T20:15:00Z,0.0,0.0752,0.0471,0.0207,0.0074,0.0,142.4,183.74,23.62
|
| 276 |
+
2026-02-20T20:30:00Z,0.0,0.0522,0.0325,0.0144,0.0053,0.0,141.61,184.37,23.7
|
| 277 |
+
2026-02-20T20:45:00Z,0.0,0.0339,0.0205,0.0095,0.0038,0.0,141.11,184.78,23.75
|
| 278 |
+
2026-02-20T21:00:00Z,0.0,0.0204,0.0127,0.0057,0.002,0.0,140.8,185.03,23.78
|
| 279 |
+
2026-02-20T21:15:00Z,0.0,0.0118,0.0072,0.0033,0.0012,0.0,140.62,185.17,23.8
|
| 280 |
+
2026-02-20T21:30:00Z,0.0,0.0064,0.004,0.0018,0.0007,0.0,140.53,185.25,23.81
|
| 281 |
+
2026-02-20T21:45:00Z,0.0,0.0032,0.002,0.0009,0.0004,0.0,140.48,185.29,23.82
|
| 282 |
+
2026-02-20T22:00:00Z,0.0,0.0015,0.0009,0.0004,0.0002,0.0,140.46,185.3,23.82
|
| 283 |
+
2026-02-20T22:15:00Z,0.0,0.0007,0.0004,0.0002,0.0001,0.0,140.45,185.31,23.82
|
| 284 |
+
2026-02-20T22:30:00Z,0.0,0.0003,0.0002,0.0001,0.0,0.0,140.44,185.32,23.82
|
| 285 |
+
2026-02-20T22:45:00Z,0.0,0.0001,0.0001,0.0,0.0,0.0,140.44,185.32,23.82
|
| 286 |
+
2026-02-20T23:00:00Z,0.0,0.0,0.0,0.0,0.0,0.0,140.44,185.32,23.82
|
| 287 |
+
2026-02-20T23:15:00Z,0.0,0.0,0.0,0.0,0.0,0.0,140.44,185.32,23.82
|
| 288 |
+
2026-02-20T23:30:00Z,0.0,0.0,0.0,0.0,0.0,0.0,140.44,185.32,23.82
|
| 289 |
+
2026-02-20T23:45:00Z,0.0,0.0,0.0,0.0,0.0,0.0,140.44,185.32,23.82
|
| 290 |
+
2026-02-21T00:00:00Z,0.0,0.0,0.0,0.0,0.0,0.0,140.44,185.32,23.82
|
| 291 |
+
2026-02-21T00:15:00Z,0.0,0.0,0.0,0.0,0.0,0.0,140.44,185.32,23.82
|
| 292 |
+
2026-02-21T00:30:00Z,0.0,0.0,0.0,0.0,0.0,0.0,140.44,185.32,23.82
|
| 293 |
+
2026-02-21T00:45:00Z,0.0,0.0,0.0,0.0,0.0,0.0,140.44,185.32,23.82
|
| 294 |
+
2026-02-21T01:00:00Z,0.0,0.0,0.0,0.0,0.0,0.0,140.44,185.32,23.82
|
| 295 |
+
2026-02-21T01:15:00Z,0.0,0.0,0.0,0.0,0.0,0.0,140.44,185.32,23.82
|
| 296 |
+
2026-02-21T01:30:00Z,0.0,0.0,0.0,0.0,0.0,0.0,140.44,185.32,23.82
|
| 297 |
+
2026-02-21T01:45:00Z,0.0,0.0,0.0,0.0,0.0,0.0,140.44,185.32,23.82
|
| 298 |
+
2026-02-21T02:00:00Z,0.0,0.0,0.0,0.0,0.0,0.0,140.44,185.32,23.82
|
| 299 |
+
2026-02-21T02:15:00Z,0.0,0.0,0.0,0.0,0.0,0.0,140.44,185.32,23.82
|
| 300 |
+
2026-02-21T02:30:00Z,0.0,0.0,0.0,0.0,0.0,0.0,140.44,185.32,23.82
|
| 301 |
+
2026-02-21T02:45:00Z,0.0,0.0,0.0,0.0,0.0,0.0,140.44,185.32,23.82
|
| 302 |
+
2026-02-21T03:00:00Z,0.0,0.0,0.0,0.0,0.0,0.0,140.44,185.32,23.82
|
| 303 |
+
2026-02-21T03:15:00Z,0.0,0.0,0.0,0.0,0.0,0.0,140.44,185.32,23.82
|
| 304 |
+
2026-02-21T03:30:00Z,0.0,0.0002,0.0001,0.0,0.0,0.0,140.44,185.32,23.82
|
| 305 |
+
2026-02-21T03:45:00Z,0.0,0.0004,0.0003,0.0001,0.0,0.0,140.43,185.32,23.82
|
| 306 |
+
2026-02-21T04:00:00Z,0.0,0.0011,0.0007,0.0003,0.0001,0.0,140.41,185.34,23.82
|
| 307 |
+
2026-02-21T04:15:00Z,0.0,0.0024,0.0015,0.0007,0.0003,0.0,140.38,185.37,23.83
|
| 308 |
+
2026-02-21T04:30:00Z,0.0,0.0052,0.0032,0.0014,0.0005,0.0,140.3,185.43,23.83
|
| 309 |
+
2026-02-21T04:45:00Z,0.0,0.0105,0.0066,0.0028,0.0011,0.0,140.14,185.56,23.85
|
| 310 |
+
2026-02-21T05:00:00Z,0.0,0.0192,0.0122,0.0052,0.0019,0.0,139.85,185.79,23.88
|
| 311 |
+
2026-02-21T05:15:00Z,0.0,0.0337,0.0209,0.0095,0.0033,0.0,139.35,186.2,23.93
|
| 312 |
+
2026-02-21T05:30:00Z,0.0,0.0528,0.0329,0.0143,0.0055,0.0,138.56,186.84,24.01
|
| 313 |
+
2026-02-21T05:45:00Z,0.0,0.0876,0.055,0.0233,0.0093,0.0,137.24,187.9,24.15
|
| 314 |
+
2026-02-21T06:00:00Z,0.0,0.1218,0.0737,0.0346,0.0134,0.0,135.42,189.27,24.35
|
| 315 |
+
2026-02-21T06:15:00Z,0.0,0.1695,0.1048,0.047,0.0177,0.0,132.87,189.27,24.62
|
| 316 |
+
2026-02-21T06:30:00Z,0.0,0.2259,0.1438,0.0599,0.0222,0.0,129.49,189.27,24.95
|
| 317 |
+
2026-02-21T06:45:00Z,0.0,0.254,0.1549,0.0728,0.0264,0.0,125.68,189.27,25.35
|
| 318 |
+
2026-02-21T07:00:00Z,0.0,0.295,0.1819,0.0817,0.0314,0.0,121.25,189.27,25.82
|
| 319 |
+
2026-02-21T07:15:00Z,0.0,0.3268,0.2073,0.0877,0.0318,0.0,116.35,189.27,26.29
|
| 320 |
+
2026-02-21T07:30:00Z,0.0,0.3215,0.2039,0.0849,0.0327,0.0,111.53,189.27,26.78
|
| 321 |
+
2026-02-21T07:45:00Z,0.0,0.3083,0.1936,0.0839,0.0308,0.0,106.9,189.27,27.25
|
| 322 |
+
2026-02-21T08:00:00Z,0.0,0.2598,0.1585,0.0736,0.0277,0.0,103.01,189.27,27.66
|
| 323 |
+
2026-02-21T08:15:00Z,0.0,0.212,0.1306,0.059,0.0223,0.0,99.83,189.27,28.0
|
| 324 |
+
2026-02-21T08:30:00Z,0.0,0.1691,0.1034,0.0467,0.019,0.0,97.29,189.27,28.28
|
| 325 |
+
2026-02-21T08:45:00Z,0.0,0.123,0.0762,0.0338,0.013,0.0,95.44,189.27,28.48
|
| 326 |
+
2026-02-21T09:00:00Z,0.0,0.0887,0.0562,0.024,0.0086,0.0,94.11,189.27,28.61
|
| 327 |
+
2026-02-21T09:15:00Z,0.0,0.0554,0.0343,0.0154,0.0056,0.0,93.28,189.27,28.69
|
| 328 |
+
2026-02-21T09:30:00Z,0.0,0.0341,0.0204,0.0099,0.0037,0.0,92.77,189.27,28.75
|
| 329 |
+
2026-02-21T09:45:00Z,0.0,0.0187,0.0115,0.0051,0.002,0.0,92.49,189.27,28.78
|
| 330 |
+
2026-02-21T10:00:00Z,0.0,0.0108,0.0067,0.003,0.0011,0.0,92.33,189.27,28.79
|
| 331 |
+
2026-02-21T10:15:00Z,0.0,0.0054,0.0033,0.0015,0.0006,0.0,92.25,189.27,28.8
|
| 332 |
+
2026-02-21T10:30:00Z,0.0,0.0027,0.0017,0.0007,0.0002,0.0,92.21,189.27,28.8
|
| 333 |
+
2026-02-21T10:45:00Z,0.0,0.0011,0.0007,0.0003,0.0001,0.0,92.19,189.27,28.81
|
| 334 |
+
2026-02-21T11:00:00Z,0.0,0.0005,0.0003,0.0001,0.0,0.0,92.19,189.27,28.81
|
| 335 |
+
2026-02-21T11:15:00Z,0.0,0.0002,0.0001,0.0,0.0,0.0,92.18,189.27,28.81
|
| 336 |
+
2026-02-21T11:30:00Z,0.0,0.0,0.0,0.0,0.0,0.0,92.18,189.27,28.81
|
| 337 |
+
2026-02-21T11:45:00Z,0.0,0.0,0.0,0.0,0.0,0.0,92.18,189.27,28.81
|
| 338 |
+
2026-02-21T12:00:00Z,0.0,0.0,0.0,0.0,0.0,0.0,92.18,189.27,28.81
|
| 339 |
+
2026-02-21T12:15:00Z,0.0,0.0,0.0,0.0,0.0,0.0,92.18,189.27,28.81
|
| 340 |
+
2026-02-21T12:30:00Z,0.0,0.0,0.0,0.0,0.0,0.0,92.18,189.27,28.81
|
| 341 |
+
2026-02-21T12:45:00Z,0.0,0.0,0.0,0.0,0.0,0.0,92.18,189.27,28.81
|
| 342 |
+
2026-02-21T13:00:00Z,0.0,0.0,0.0,0.0,0.0,0.0,92.18,189.27,28.81
|
| 343 |
+
2026-02-21T13:15:00Z,0.0,0.0,0.0,0.0,0.0,0.0,92.18,189.27,28.81
|
| 344 |
+
2026-02-21T13:30:00Z,0.0,0.0,0.0,0.0,0.0,0.0,92.18,189.27,28.81
|
| 345 |
+
2026-02-21T13:45:00Z,0.0,0.0,0.0,0.0,0.0,0.0,92.18,189.27,28.81
|
| 346 |
+
2026-02-21T14:00:00Z,0.0,0.0,0.0,0.0,0.0,0.0,92.18,189.27,28.81
|
| 347 |
+
2026-02-21T14:15:00Z,0.0,0.0,0.0,0.0,0.0,0.0,92.18,189.27,28.81
|
| 348 |
+
2026-02-21T14:30:00Z,0.0,0.0,0.0,0.0,0.0,0.0,92.18,189.27,28.81
|
| 349 |
+
2026-02-21T14:45:00Z,0.0,0.0,0.0,0.0,0.0,0.0,92.18,189.27,28.81
|
| 350 |
+
2026-02-21T15:00:00Z,0.0,0.0001,0.0001,0.0,0.0,0.0,92.18,189.27,28.81
|
| 351 |
+
2026-02-21T15:15:00Z,0.0,0.0003,0.0002,0.0001,0.0,0.0,92.18,189.27,28.81
|
| 352 |
+
2026-02-21T15:30:00Z,0.0,0.0006,0.0004,0.0002,0.0001,0.0,92.17,189.27,28.81
|
| 353 |
+
2026-02-21T15:45:00Z,0.0,0.0015,0.001,0.0004,0.0001,0.0,92.15,189.27,28.81
|
| 354 |
+
2026-02-21T16:00:00Z,0.0,0.003,0.0018,0.0009,0.0003,0.0,92.1,189.27,28.82
|
| 355 |
+
2026-02-21T16:15:00Z,0.0,0.0058,0.0035,0.0017,0.0006,0.0,92.01,189.27,28.82
|
| 356 |
+
2026-02-21T16:30:00Z,0.0,0.0107,0.0064,0.0031,0.0012,0.0,91.85,189.27,28.84
|
| 357 |
+
2026-02-21T16:45:00Z,0.0,0.02,0.0126,0.0053,0.0021,0.0,91.55,189.27,28.87
|
| 358 |
+
2026-02-21T17:00:00Z,0.0,0.0309,0.0183,0.0089,0.0037,0.0,91.09,189.27,28.93
|
| 359 |
+
2026-02-21T17:15:00Z,0.0,0.0518,0.033,0.0139,0.0049,0.0,90.31,189.27,29.0
|
| 360 |
+
2026-02-21T17:30:00Z,0.0,0.0736,0.0452,0.0206,0.0077,0.0,89.21,189.27,29.12
|
| 361 |
+
2026-02-21T17:45:00Z,0.0,0.1003,0.0621,0.0279,0.0102,0.0,87.7,189.27,29.27
|
| 362 |
+
2026-02-21T18:00:00Z,0.0,0.1239,0.0751,0.0358,0.013,0.0,85.84,189.27,29.47
|
| 363 |
+
2026-02-21T18:15:00Z,0.0,0.157,0.0975,0.0431,0.0164,0.0,83.49,189.27,29.71
|
| 364 |
+
2026-02-21T18:30:00Z,0.0,0.178,0.1129,0.0475,0.0176,0.0,80.82,189.27,29.98
|
| 365 |
+
2026-02-21T18:45:00Z,0.0,0.1895,0.1191,0.0519,0.0185,0.0,77.98,189.27,30.25
|
| 366 |
+
2026-02-21T19:00:00Z,0.0,0.1846,0.1138,0.0519,0.0189,0.0,75.21,189.27,30.54
|
| 367 |
+
2026-02-21T19:15:00Z,0.0,0.1723,0.1066,0.0487,0.017,0.0,72.62,189.27,30.79
|
| 368 |
+
2026-02-21T19:30:00Z,0.0,0.1566,0.0939,0.0452,0.0175,0.0,70.27,189.27,31.05
|
| 369 |
+
2026-02-21T19:45:00Z,0.0,0.13,0.0791,0.0371,0.0138,0.0,68.32,189.27,31.26
|
| 370 |
+
2026-02-21T20:00:00Z,0.0,0.102,0.0629,0.0286,0.0106,0.0,66.79,189.27,31.42
|
| 371 |
+
2026-02-21T20:15:00Z,0.0,0.0743,0.0472,0.0203,0.0068,0.0,65.68,189.27,31.52
|
| 372 |
+
2026-02-21T20:30:00Z,0.0,0.0543,0.0343,0.0148,0.0052,0.0,64.87,189.27,31.6
|
| 373 |
+
2026-02-21T20:45:00Z,0.0,0.0338,0.0211,0.0092,0.0035,0.0,64.36,189.27,31.65
|
| 374 |
+
2026-02-21T21:00:00Z,0.0,0.0212,0.0134,0.0057,0.0021,0.0,64.04,189.27,31.68
|
| 375 |
+
2026-02-21T21:15:00Z,0.0,0.0115,0.0072,0.003,0.0013,0.0,63.87,189.27,31.7
|
| 376 |
+
2026-02-21T21:30:00Z,0.0,0.0063,0.0039,0.0018,0.0006,0.0,63.77,189.27,31.71
|
| 377 |
+
2026-02-21T21:45:00Z,0.0,0.0033,0.002,0.0009,0.0004,0.0,63.72,189.27,31.72
|
| 378 |
+
2026-02-21T22:00:00Z,0.0,0.0015,0.0009,0.0004,0.0002,0.0,63.7,189.27,31.72
|
| 379 |
+
2026-02-21T22:15:00Z,0.0,0.0007,0.0004,0.0002,0.0001,0.0,63.69,189.27,31.72
|
| 380 |
+
2026-02-21T22:30:00Z,0.0,0.0003,0.0002,0.0001,0.0,0.0,63.69,189.27,31.72
|
| 381 |
+
2026-02-21T22:45:00Z,0.0,0.0001,0.0001,0.0,0.0,0.0,63.69,189.27,31.72
|
| 382 |
+
2026-02-21T23:00:00Z,0.0,0.0,0.0,0.0,0.0,0.0,63.69,189.27,31.72
|
| 383 |
+
2026-02-21T23:15:00Z,0.0,0.0,0.0,0.0,0.0,0.0,63.69,189.27,31.72
|
| 384 |
+
2026-02-21T23:30:00Z,0.0,0.0,0.0,0.0,0.0,0.0,63.69,189.27,31.72
|
| 385 |
+
2026-02-21T23:45:00Z,0.0,0.0,0.0,0.0,0.0,0.0,63.69,189.27,31.72
|
output/water/1DAY.csv
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Time,Inlet_Total_L,Pump_Total_L,Shower_Total_L,Kitchen_Total_L,Toilet_Total_L,Unmetered_Total_L,FreshTank_Level_L,FreshTank_Level_Pct,GreyTank_Level_L,GreyTank_Level_Pct,BlackTank_Level_L,BlackTank_Level_Pct
|
| 2 |
+
2026-02-18T00:00:00Z,10.554,76.638,47.5783,21.1458,7.9139,0.0,293.53,77.54,61.85,32.68,7.91,4.64
|
| 3 |
+
2026-02-19T00:00:00Z,0.0,76.6258,47.3512,21.3447,7.9299,0.0,216.9,57.3,123.68,65.35,15.84,9.3
|
| 4 |
+
2026-02-20T00:00:00Z,0.0,76.4636,47.0497,21.4373,7.9766,0.0,140.44,37.1,185.32,97.91,23.82,13.98
|
| 5 |
+
2026-02-21T00:00:00Z,0.0,76.7549,47.6639,21.1903,7.9007,0.0,63.69,16.83,189.27,100.0,31.72,18.62
|
output/water/1H.csv
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Time,Inlet_Total_L,Pump_Total_L,Shower_Total_L,Kitchen_Total_L,Toilet_Total_L,Unmetered_Total_L,FreshTank_Level_L,FreshTank_Level_Pct,GreyTank_Level_L,GreyTank_Level_Pct,BlackTank_Level_L,BlackTank_Level_Pct
|
| 2 |
+
2026-02-18T00:00:00Z,0.0,0.0,0.0,0.0,0.0,0,359.61,95.0,0.0,0.0,0.0,0.0
|
| 3 |
+
2026-02-18T01:00:00Z,0.0,0.0,0.0,0.0,0.0,0,359.61,95.0,0.0,0.0,0.0,0.0
|
| 4 |
+
2026-02-18T02:00:00Z,0.0,0.0,0.0,0.0,0.0,0,359.61,95.0,0.0,0.0,0.0,0.0
|
| 5 |
+
2026-02-18T03:00:00Z,0.0,0.0092,0.0062,0.0025,0.0005,0.0,359.6,95.0,0.01,0.01,0.0,0.0
|
| 6 |
+
2026-02-18T04:00:00Z,0.0,0.2746,0.1681,0.0774,0.0291,0.0,359.33,94.92,0.23,0.12,0.03,0.02
|
| 7 |
+
2026-02-18T05:00:00Z,0.0,2.8425,1.7569,0.7879,0.2977,0.0,356.49,94.17,2.52,1.33,0.33,0.19
|
| 8 |
+
2026-02-18T06:00:00Z,0.0,11.4825,7.1884,3.1167,1.1774,0.0,345.01,91.14,11.79,6.23,1.5,0.88
|
| 9 |
+
2026-02-18T07:00:00Z,10.554,18.4286,11.4952,5.065,1.8684,0.0,337.13,89.06,26.7,14.11,3.37,1.98
|
| 10 |
+
2026-02-18T08:00:00Z,0.0,11.7782,7.3056,3.2225,1.2501,0.0,325.35,85.95,36.17,19.11,4.62,2.71
|
| 11 |
+
2026-02-18T09:00:00Z,0.0,2.8574,1.7167,0.8303,0.3104,0.0,322.49,85.19,38.47,20.33,4.93,2.89
|
| 12 |
+
2026-02-18T10:00:00Z,0.0,0.2863,0.1751,0.0809,0.0303,0.0,322.21,85.12,38.7,20.45,4.96,2.91
|
| 13 |
+
2026-02-18T11:00:00Z,0.0,0.0099,0.0064,0.003,0.0005,0.0,322.2,85.12,38.7,20.45,4.96,2.91
|
| 14 |
+
2026-02-18T12:00:00Z,0.0,0.0,0.0,0.0,0.0,0,322.2,85.12,38.7,20.45,4.96,2.91
|
| 15 |
+
2026-02-18T13:00:00Z,0.0,0.0,0.0,0.0,0.0,0,322.2,85.12,38.7,20.45,4.96,2.91
|
| 16 |
+
2026-02-18T14:00:00Z,0.0,0.0,0.0,0.0,0.0,0,322.2,85.12,38.7,20.45,4.96,2.91
|
| 17 |
+
2026-02-18T15:00:00Z,0.0,0.036,0.0227,0.01,0.0033,0.0,322.16,85.11,38.73,20.46,4.97,2.92
|
| 18 |
+
2026-02-18T16:00:00Z,0.0,0.6267,0.3916,0.171,0.0641,0.0,321.54,84.94,39.24,20.73,5.03,2.95
|
| 19 |
+
2026-02-18T17:00:00Z,0.0,3.94,2.4291,1.094,0.4169,0.0,317.6,83.9,42.41,22.41,5.45,3.2
|
| 20 |
+
2026-02-18T18:00:00Z,0.0,9.6751,5.9574,2.7049,1.0128,0.0,307.92,81.34,50.21,26.53,6.46,3.79
|
| 21 |
+
2026-02-18T19:00:00Z,0.0,9.8604,6.1813,2.703,0.9761,0.0,298.06,78.74,58.2,30.75,7.44,4.37
|
| 22 |
+
2026-02-18T20:00:00Z,0.0,3.8651,2.3665,1.0933,0.4053,0.0,294.2,77.72,61.32,32.4,7.84,4.6
|
| 23 |
+
2026-02-18T21:00:00Z,0.0,0.628,0.3878,0.1729,0.0673,0.0,293.57,77.55,61.82,32.66,7.91,4.64
|
| 24 |
+
2026-02-18T22:00:00Z,0.0,0.0375,0.0233,0.0105,0.0037,0.0,293.53,77.54,61.85,32.68,7.91,4.64
|
| 25 |
+
2026-02-18T23:00:00Z,0.0,0.0,0.0,0.0,0.0,0,293.53,77.54,61.85,32.68,7.91,4.64
|
| 26 |
+
2026-02-19T00:00:00Z,0.0,0.0,0.0,0.0,0.0,0,293.53,77.54,61.85,32.68,7.91,4.64
|
| 27 |
+
2026-02-19T01:00:00Z,0.0,0.0,0.0,0.0,0.0,0,293.53,77.54,61.85,32.68,7.91,4.64
|
| 28 |
+
2026-02-19T02:00:00Z,0.0,0.0,0.0,0.0,0.0,0,293.53,77.54,61.85,32.68,7.91,4.64
|
| 29 |
+
2026-02-19T03:00:00Z,0.0,0.0091,0.006,0.0026,0.0005,0.0,293.52,77.54,61.86,32.68,7.91,4.64
|
| 30 |
+
2026-02-19T04:00:00Z,0.0,0.276,0.1675,0.0798,0.0287,0.0,293.24,77.47,62.08,32.8,7.94,4.66
|
| 31 |
+
2026-02-19T05:00:00Z,0.0,2.8554,1.7745,0.7724,0.3085,0.0,290.39,76.71,64.37,34.01,8.25,4.84
|
| 32 |
+
2026-02-19T06:00:00Z,0.0,11.3203,6.9281,3.1922,1.2,0.0,279.07,73.72,73.48,38.82,9.45,5.55
|
| 33 |
+
2026-02-19T07:00:00Z,0.0,18.4076,11.4041,5.1151,1.8884,0.0,260.66,68.86,88.35,46.68,11.34,6.66
|
| 34 |
+
2026-02-19T08:00:00Z,0.0,11.8492,7.3657,3.2469,1.2366,0.0,248.81,65.73,97.9,51.72,12.58,7.39
|
| 35 |
+
2026-02-19T09:00:00Z,0.0,3.0474,1.9177,0.8276,0.3021,0.0,245.76,64.92,100.37,53.03,12.88,7.56
|
| 36 |
+
2026-02-19T10:00:00Z,0.0,0.2934,0.1796,0.0816,0.0322,0.0,245.47,64.85,100.61,53.16,12.91,7.58
|
| 37 |
+
2026-02-19T11:00:00Z,0.0,0.01,0.0068,0.0028,0.0004,0.0,245.46,64.84,100.62,53.16,12.91,7.58
|
| 38 |
+
2026-02-19T12:00:00Z,0.0,0.0,0.0,0.0,0.0,0,245.46,64.84,100.62,53.16,12.91,7.58
|
| 39 |
+
2026-02-19T13:00:00Z,0.0,0.0,0.0,0.0,0.0,0,245.46,64.84,100.62,53.16,12.91,7.58
|
| 40 |
+
2026-02-19T14:00:00Z,0.0,0.0,0.0,0.0,0.0,0,245.46,64.84,100.62,53.16,12.91,7.58
|
| 41 |
+
2026-02-19T15:00:00Z,0.0,0.0358,0.0225,0.01,0.0033,0.0,245.43,64.84,100.64,53.17,12.91,7.58
|
| 42 |
+
2026-02-19T16:00:00Z,0.0,0.6173,0.3825,0.1677,0.0671,0.0,244.81,64.67,101.14,53.44,12.98,7.62
|
| 43 |
+
2026-02-19T17:00:00Z,0.0,3.9726,2.472,1.0923,0.4083,0.0,240.84,63.62,104.35,55.13,13.39,7.86
|
| 44 |
+
2026-02-19T18:00:00Z,0.0,9.6008,5.8913,2.6925,1.017,0.0,231.24,61.09,112.07,59.21,14.41,8.46
|
| 45 |
+
2026-02-19T19:00:00Z,0.0,9.7421,5.9861,2.7796,0.9764,0.0,221.49,58.51,119.96,63.38,15.38,9.03
|
| 46 |
+
2026-02-19T20:00:00Z,0.0,3.9207,2.4269,1.1019,0.3919,0.0,217.57,57.48,123.14,65.06,15.78,9.26
|
| 47 |
+
2026-02-19T21:00:00Z,0.0,0.6292,0.3952,0.1691,0.0649,0.0,216.94,57.31,123.65,65.33,15.84,9.3
|
| 48 |
+
2026-02-19T22:00:00Z,0.0,0.0389,0.0247,0.0106,0.0036,0.0,216.9,57.3,123.68,65.35,15.84,9.3
|
| 49 |
+
2026-02-19T23:00:00Z,0.0,0.0,0.0,0.0,0.0,0,216.9,57.3,123.68,65.35,15.84,9.3
|
| 50 |
+
2026-02-20T00:00:00Z,0.0,0.0,0.0,0.0,0.0,0,216.9,57.3,123.68,65.35,15.84,9.3
|
| 51 |
+
2026-02-20T01:00:00Z,0.0,0.0,0.0,0.0,0.0,0,216.9,57.3,123.68,65.35,15.84,9.3
|
| 52 |
+
2026-02-20T02:00:00Z,0.0,0.0,0.0,0.0,0.0,0,216.9,57.3,123.68,65.35,15.84,9.3
|
| 53 |
+
2026-02-20T03:00:00Z,0.0,0.009,0.0058,0.0024,0.0008,0.0,216.9,57.3,123.69,65.35,15.84,9.3
|
| 54 |
+
2026-02-20T04:00:00Z,0.0,0.2834,0.1753,0.0791,0.029,0.0,216.61,57.22,123.91,65.47,15.87,9.32
|
| 55 |
+
2026-02-20T05:00:00Z,0.0,2.8096,1.7248,0.7924,0.2924,0.0,213.8,56.48,126.18,66.67,16.17,9.49
|
| 56 |
+
2026-02-20T06:00:00Z,0.0,11.6232,7.2033,3.2576,1.1623,0.0,202.18,53.41,135.59,71.64,17.33,10.17
|
| 57 |
+
2026-02-20T07:00:00Z,0.0,18.0831,10.9966,5.156,1.9305,0.0,184.1,48.63,150.13,79.32,19.26,11.31
|
| 58 |
+
2026-02-20T08:00:00Z,0.0,11.7606,7.2625,3.2684,1.2297,0.0,172.34,45.53,159.61,84.33,20.49,12.03
|
| 59 |
+
2026-02-20T09:00:00Z,0.0,2.9139,1.7728,0.8214,0.3197,0.0,169.42,44.76,161.94,85.56,20.81,12.22
|
| 60 |
+
2026-02-20T10:00:00Z,0.0,0.2872,0.1785,0.0804,0.0283,0.0,169.13,44.68,162.18,85.69,20.84,12.23
|
| 61 |
+
2026-02-20T11:00:00Z,0.0,0.0103,0.0071,0.0026,0.0006,0.0,169.12,44.68,162.19,85.69,20.84,12.23
|
| 62 |
+
2026-02-20T12:00:00Z,0.0,0.0,0.0,0.0,0.0,0,169.12,44.68,162.19,85.69,20.84,12.23
|
| 63 |
+
2026-02-20T13:00:00Z,0.0,0.0,0.0,0.0,0.0,0,169.12,44.68,162.19,85.69,20.84,12.23
|
| 64 |
+
2026-02-20T14:00:00Z,0.0,0.0,0.0,0.0,0.0,0,169.12,44.68,162.19,85.69,20.84,12.23
|
| 65 |
+
2026-02-20T15:00:00Z,0.0,0.0353,0.0225,0.0098,0.003,0.0,169.09,44.67,162.22,85.71,20.84,12.23
|
| 66 |
+
2026-02-20T16:00:00Z,0.0,0.6016,0.3689,0.1684,0.0643,0.0,168.49,44.51,162.7,85.96,20.9,12.27
|
| 67 |
+
2026-02-20T17:00:00Z,0.0,3.8733,2.4396,1.071,0.3627,0.0,164.61,43.49,165.86,87.63,21.27,12.49
|
| 68 |
+
2026-02-20T18:00:00Z,0.0,9.6489,5.9556,2.6714,1.0219,0.0,154.96,40.94,173.62,91.73,22.29,13.09
|
| 69 |
+
2026-02-20T19:00:00Z,0.0,9.8755,6.024,2.7937,1.0578,0.0,145.09,38.33,181.56,95.93,23.35,13.71
|
| 70 |
+
2026-02-20T20:00:00Z,0.0,3.984,2.5001,1.0775,0.4064,0.0,141.11,37.28,184.78,97.63,23.75,13.94
|
| 71 |
+
2026-02-20T21:00:00Z,0.0,0.6272,0.3884,0.175,0.0638,0.0,140.48,37.11,185.29,97.9,23.82,13.98
|
| 72 |
+
2026-02-20T22:00:00Z,0.0,0.0375,0.0239,0.0102,0.0034,0.0,140.44,37.1,185.32,97.91,23.82,13.98
|
| 73 |
+
2026-02-20T23:00:00Z,0.0,0.0,0.0,0.0,0.0,0,140.44,37.1,185.32,97.91,23.82,13.98
|
| 74 |
+
2026-02-21T00:00:00Z,0.0,0.0,0.0,0.0,0.0,0,140.44,37.1,185.32,97.91,23.82,13.98
|
| 75 |
+
2026-02-21T01:00:00Z,0.0,0.0,0.0,0.0,0.0,0,140.44,37.1,185.32,97.91,23.82,13.98
|
| 76 |
+
2026-02-21T02:00:00Z,0.0,0.0,0.0,0.0,0.0,0,140.44,37.1,185.32,97.91,23.82,13.98
|
| 77 |
+
2026-02-21T03:00:00Z,0.0,0.0095,0.0065,0.0025,0.0005,0.0,140.43,37.1,185.32,97.91,23.82,13.98
|
| 78 |
+
2026-02-21T04:00:00Z,0.0,0.2884,0.1804,0.0785,0.0295,0.0,140.14,37.02,185.56,98.04,23.85,14.0
|
| 79 |
+
2026-02-21T05:00:00Z,0.0,2.8995,1.8152,0.7841,0.3002,0.0,137.24,36.25,187.9,99.28,24.15,14.18
|
| 80 |
+
2026-02-21T06:00:00Z,0.0,11.5674,7.1575,3.2144,1.1955,0.0,125.68,33.2,189.27,100.0,25.35,14.88
|
| 81 |
+
2026-02-21T07:00:00Z,0.0,18.7733,11.8003,5.0715,1.9015,0.0,106.9,28.24,189.27,100.0,27.25,16.0
|
| 82 |
+
2026-02-21T08:00:00Z,0.0,11.4578,7.031,3.1968,1.23,0.0,95.44,25.21,189.27,100.0,28.48,16.72
|
| 83 |
+
2026-02-21T09:00:00Z,0.0,2.9528,1.8373,0.8171,0.2984,0.0,92.49,24.43,189.27,100.0,28.78,16.9
|
| 84 |
+
2026-02-21T10:00:00Z,0.0,0.2995,0.1855,0.0833,0.0307,0.0,92.19,24.35,189.27,100.0,28.81,16.91
|
| 85 |
+
2026-02-21T11:00:00Z,0.0,0.0098,0.0064,0.0027,0.0007,0.0,92.18,24.35,189.27,100.0,28.81,16.91
|
| 86 |
+
2026-02-21T12:00:00Z,0.0,0.0,0.0,0.0,0.0,0,92.18,24.35,189.27,100.0,28.81,16.91
|
| 87 |
+
2026-02-21T13:00:00Z,0.0,0.0,0.0,0.0,0.0,0,92.18,24.35,189.27,100.0,28.81,16.91
|
| 88 |
+
2026-02-21T14:00:00Z,0.0,0.0,0.0,0.0,0.0,0,92.18,24.35,189.27,100.0,28.81,16.91
|
| 89 |
+
2026-02-21T15:00:00Z,0.0,0.0363,0.0235,0.0093,0.0035,0.0,92.15,24.34,189.27,100.0,28.81,16.91
|
| 90 |
+
2026-02-21T16:00:00Z,0.0,0.5942,0.3652,0.1655,0.0635,0.0,91.55,24.18,189.27,100.0,28.87,16.95
|
| 91 |
+
2026-02-21T17:00:00Z,0.0,3.8488,2.3794,1.0711,0.3983,0.0,87.7,23.17,189.27,100.0,29.27,17.18
|
| 92 |
+
2026-02-21T18:00:00Z,0.0,9.7271,6.0705,2.6744,0.9822,0.0,77.98,20.6,189.27,100.0,30.25,17.76
|
| 93 |
+
2026-02-21T19:00:00Z,0.0,9.6521,5.9017,2.7439,1.0065,0.0,68.32,18.05,189.27,100.0,31.26,18.35
|
| 94 |
+
2026-02-21T20:00:00Z,0.0,3.9649,2.4809,1.0946,0.3894,0.0,64.36,17.0,189.27,100.0,31.65,18.58
|
| 95 |
+
2026-02-21T21:00:00Z,0.0,0.6353,0.3986,0.1701,0.0666,0.0,63.72,16.83,189.27,100.0,31.72,18.62
|
| 96 |
+
2026-02-21T22:00:00Z,0.0,0.0382,0.024,0.0105,0.0037,0.0,63.69,16.83,189.27,100.0,31.72,18.62
|
| 97 |
+
2026-02-21T23:00:00Z,0.0,0.0,0.0,0.0,0.0,0,63.69,16.83,189.27,100.0,31.72,18.62
|
output/water/1MIN.csv
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
requirements.txt
CHANGED
|
@@ -1,4 +1,2 @@
|
|
| 1 |
-
fastapi
|
| 2 |
-
uvicorn
|
| 3 |
-
pydantic
|
| 4 |
-
aiofiles
|
|
|
|
| 1 |
+
fastapi>=0.109.0
|
| 2 |
+
uvicorn[standard]>=0.27.0
|
|
|
|
|
|
stability_index.py
ADDED
|
@@ -0,0 +1,593 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Stability Index Engine
|
| 3 |
+
======================
|
| 4 |
+
Computes a deterministic composite risk score SI β [0, 10] per minute
|
| 5 |
+
from the generated power and water 1MIN CSV files.
|
| 6 |
+
|
| 7 |
+
Formula (v1.0 β matches stability_index_spec.docx):
|
| 8 |
+
|
| 9 |
+
SI(t) = SI_raw(t) Γ V_dep(t)
|
| 10 |
+
|
| 11 |
+
SI_raw = 10 Γ (w_batΒ·C_bat + w_freshΒ·C_fresh + w_wasteΒ·C_waste
|
| 12 |
+
+ w_energyΒ·C_energy + w_stableΒ·C_stable)
|
| 13 |
+
|
| 14 |
+
V_dep = clamp(ttc / horizon_hr, 0.5, 1.0)
|
| 15 |
+
where ttc = min(time_to_crit_battery, time_to_crit_fresh) [hours]
|
| 16 |
+
|
| 17 |
+
Output CSV columns:
|
| 18 |
+
Time, SI, SI_raw, C_bat, C_fresh, C_waste, C_grey, C_black,
|
| 19 |
+
C_energy, C_stable, V_dep, ttc_hr, band, warm_up,
|
| 20 |
+
Battery_Level_Pct, FreshTank_Level_L, GreyTank_Level_L, BlackTank_Level_L
|
| 21 |
+
|
| 22 |
+
Usage:
|
| 23 |
+
python stability_index.py # uses ./output/
|
| 24 |
+
python stability_index.py --power_dir data/power --water_dir data/water
|
| 25 |
+
python stability_index.py --config si_config.json --out si_scores.csv
|
| 26 |
+
python stability_index.py --summary
|
| 27 |
+
"""
|
| 28 |
+
|
| 29 |
+
import csv
|
| 30 |
+
import json
|
| 31 |
+
import math
|
| 32 |
+
import argparse
|
| 33 |
+
import statistics
|
| 34 |
+
from collections import deque
|
| 35 |
+
from pathlib import Path
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 39 |
+
# DEFAULT CONFIGURATION
|
| 40 |
+
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 41 |
+
|
| 42 |
+
DEFAULT_CONFIG = {
|
| 43 |
+
# --- Component weights (must sum to 1.0) ---
|
| 44 |
+
"w_bat": 0.35,
|
| 45 |
+
"w_fresh": 0.25,
|
| 46 |
+
"w_waste": 0.12,
|
| 47 |
+
"w_energy": 0.18,
|
| 48 |
+
"w_stable": 0.10,
|
| 49 |
+
|
| 50 |
+
# --- Battery thresholds (%) ---
|
| 51 |
+
"bat_crit_pct": 20.0,
|
| 52 |
+
"bat_warn_pct": 50.0,
|
| 53 |
+
|
| 54 |
+
# --- Fresh water thresholds (%) ---
|
| 55 |
+
"fresh_crit_pct": 15.0,
|
| 56 |
+
"fresh_warn_pct": 40.0,
|
| 57 |
+
|
| 58 |
+
# --- Tank capacities (litres) ---
|
| 59 |
+
"fresh_cap_L": 378.541, # 100 gal
|
| 60 |
+
"grey_cap_L": 189.271, # 50 gal
|
| 61 |
+
"black_cap_L": 170.344, # 45 gal
|
| 62 |
+
|
| 63 |
+
# --- Waste tank penalty start (fill fraction 0β1) ---
|
| 64 |
+
"grey_penalty_start": 0.70,
|
| 65 |
+
"black_penalty_start": 0.60,
|
| 66 |
+
|
| 67 |
+
# --- Waste composite weights ---
|
| 68 |
+
"grey_weight_in_waste": 0.60,
|
| 69 |
+
"black_weight_in_waste": 0.40,
|
| 70 |
+
|
| 71 |
+
# --- Energy balance (C_energy) ---
|
| 72 |
+
"energy_window_min": 60,
|
| 73 |
+
"solar_cap_kW": 5.25,
|
| 74 |
+
|
| 75 |
+
# --- Consumption stability (C_stable) ---
|
| 76 |
+
"stable_window_min": 30,
|
| 77 |
+
"stable_k": 2.0,
|
| 78 |
+
"stable_mu_floor": 0.05,
|
| 79 |
+
|
| 80 |
+
# --- Depletion velocity modifier (V_dep) ---
|
| 81 |
+
"velocity_window_min": 60,
|
| 82 |
+
"velocity_horizon_hr": 4.0,
|
| 83 |
+
"velocity_min_factor": 0.5,
|
| 84 |
+
|
| 85 |
+
# --- Score band thresholds ---
|
| 86 |
+
"bands": [
|
| 87 |
+
{"min": 8.0, "max": 10.0, "label": "Excellent"},
|
| 88 |
+
{"min": 6.0, "max": 8.0, "label": "Good"},
|
| 89 |
+
{"min": 4.0, "max": 6.0, "label": "Fair"},
|
| 90 |
+
{"min": 2.0, "max": 4.0, "label": "Poor"},
|
| 91 |
+
{"min": 0.0, "max": 2.0, "label": "Critical"},
|
| 92 |
+
],
|
| 93 |
+
}
|
| 94 |
+
|
| 95 |
+
LOAD_COLS = [
|
| 96 |
+
"HVAC_Flow_kW", "Lighting_Flow_kW", "Devices_Flow_kW", "Fridge_Flow_kW",
|
| 97 |
+
"WaterPump_Flow_kW", "Cooking_Flow_kW", "Inverter_Flow_kW", "Unmetered_Flow_kW",
|
| 98 |
+
]
|
| 99 |
+
|
| 100 |
+
|
| 101 |
+
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 102 |
+
# HELPERS
|
| 103 |
+
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 104 |
+
|
| 105 |
+
def clamp(val, lo, hi):
|
| 106 |
+
return max(lo, min(hi, val))
|
| 107 |
+
|
| 108 |
+
|
| 109 |
+
def band_label(si, bands):
|
| 110 |
+
for b in bands:
|
| 111 |
+
if b["min"] <= si <= b["max"]:
|
| 112 |
+
return b["label"]
|
| 113 |
+
return "Critical"
|
| 114 |
+
|
| 115 |
+
|
| 116 |
+
def load_config(path):
|
| 117 |
+
cfg = dict(DEFAULT_CONFIG)
|
| 118 |
+
if path:
|
| 119 |
+
with open(path) as f:
|
| 120 |
+
cfg.update(json.load(f))
|
| 121 |
+
total_w = cfg["w_bat"] + cfg["w_fresh"] + cfg["w_waste"] + cfg["w_energy"] + cfg["w_stable"]
|
| 122 |
+
if abs(total_w - 1.0) > 1e-6:
|
| 123 |
+
raise ValueError(f"Component weights must sum to 1.0, got {total_w:.6f}")
|
| 124 |
+
return cfg
|
| 125 |
+
|
| 126 |
+
|
| 127 |
+
def load_csv(path):
|
| 128 |
+
with open(path, newline="") as f:
|
| 129 |
+
return list(csv.DictReader(f))
|
| 130 |
+
|
| 131 |
+
|
| 132 |
+
def merge_rows(power_rows, water_rows):
|
| 133 |
+
"""Inner join power + water rows on Time. Both files must be from same 1MIN export."""
|
| 134 |
+
if len(power_rows) == len(water_rows):
|
| 135 |
+
merged = []
|
| 136 |
+
for i, (p, w) in enumerate(zip(power_rows, water_rows)):
|
| 137 |
+
if p["Time"] != w["Time"]:
|
| 138 |
+
raise ValueError(
|
| 139 |
+
f"Timestamp mismatch at row {i}: power={p['Time']} water={w['Time']}"
|
| 140 |
+
)
|
| 141 |
+
merged.append({**p, **w})
|
| 142 |
+
return merged
|
| 143 |
+
# Fallback: join by timestamp key
|
| 144 |
+
water_idx = {r["Time"]: r for r in water_rows}
|
| 145 |
+
return [{**p, **water_idx[p["Time"]]} for p in power_rows if p["Time"] in water_idx]
|
| 146 |
+
|
| 147 |
+
|
| 148 |
+
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 149 |
+
# COMPONENT SCORE FUNCTIONS
|
| 150 |
+
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 151 |
+
|
| 152 |
+
def c_bat(bat_pct, crit, warn):
|
| 153 |
+
"""
|
| 154 |
+
Piecewise linear Battery SOC score β [0, 1].
|
| 155 |
+
|
| 156 |
+
Zones (configurable via crit/warn thresholds):
|
| 157 |
+
[0, crit) β [0.00, 0.30) steep penalty
|
| 158 |
+
[crit, warn) β [0.30, 0.70) moderate penalty
|
| 159 |
+
[warn, 100] β [0.70, 1.00] comfort zone
|
| 160 |
+
"""
|
| 161 |
+
p = clamp(bat_pct, 0.0, 100.0) / 100.0
|
| 162 |
+
c = crit / 100.0
|
| 163 |
+
w = warn / 100.0
|
| 164 |
+
if p < c:
|
| 165 |
+
return 0.00 + 0.30 * (p / c)
|
| 166 |
+
elif p < w:
|
| 167 |
+
return 0.30 + 0.40 * ((p - c) / (w - c))
|
| 168 |
+
else:
|
| 169 |
+
return 0.70 + 0.30 * ((p - w) / (1.0 - w))
|
| 170 |
+
|
| 171 |
+
|
| 172 |
+
def c_fresh(fresh_L, cap_L, crit_pct, warn_pct):
|
| 173 |
+
"""
|
| 174 |
+
Piecewise linear Fresh Water score β identical formula to c_bat,
|
| 175 |
+
applied to fill percentage. β [0, 1].
|
| 176 |
+
"""
|
| 177 |
+
pct = clamp(fresh_L / cap_L * 100.0, 0.0, 100.0)
|
| 178 |
+
return c_bat(pct, crit_pct, warn_pct)
|
| 179 |
+
|
| 180 |
+
|
| 181 |
+
def headroom_score(fill, penalty_start):
|
| 182 |
+
"""
|
| 183 |
+
Single-tank waste headroom score.
|
| 184 |
+
fill : fraction of tank capacity used [0, 1]
|
| 185 |
+
penalty_start : fill fraction above which extra penalty applies
|
| 186 |
+
|
| 187 |
+
Linear headroom below penalty_start; steeply penalised above.
|
| 188 |
+
Returns 1.0 (empty) β 0.0 (overflow).
|
| 189 |
+
"""
|
| 190 |
+
fill = clamp(fill, 0.0, 1.0)
|
| 191 |
+
headroom = 1.0 - fill
|
| 192 |
+
if fill <= penalty_start:
|
| 193 |
+
return headroom
|
| 194 |
+
excess = fill - penalty_start
|
| 195 |
+
range_above = 1.0 - penalty_start
|
| 196 |
+
factor = 1.0 - 3.0 * excess / range_above
|
| 197 |
+
return clamp(headroom * factor, 0.0, 1.0)
|
| 198 |
+
|
| 199 |
+
|
| 200 |
+
def c_waste(grey_L, black_L, grey_cap, black_cap,
|
| 201 |
+
grey_penalty, black_penalty, grey_w, black_w):
|
| 202 |
+
"""
|
| 203 |
+
Composite waste headroom = grey_w Γ C_grey + black_w Γ C_black.
|
| 204 |
+
Returns (C_waste, C_grey, C_black).
|
| 205 |
+
"""
|
| 206 |
+
cg = headroom_score(grey_L / grey_cap, grey_penalty)
|
| 207 |
+
cb = headroom_score(black_L / black_cap, black_penalty)
|
| 208 |
+
return grey_w * cg + black_w * cb, cg, cb
|
| 209 |
+
|
| 210 |
+
|
| 211 |
+
def c_energy(gen_window, load_window, solar_cap_kw):
|
| 212 |
+
"""
|
| 213 |
+
Rolling-window energy balance.
|
| 214 |
+
net_norm = clamp((mean_gen - mean_load) / solar_cap, -1, +1)
|
| 215 |
+
C_energy = 0.5 + 0.5 Γ net_norm
|
| 216 |
+
"""
|
| 217 |
+
if not gen_window:
|
| 218 |
+
return 0.5
|
| 219 |
+
gen_mean = sum(gen_window) / len(gen_window)
|
| 220 |
+
load_mean = sum(load_window) / len(load_window)
|
| 221 |
+
net_norm = clamp((gen_mean - load_mean) / max(solar_cap_kw, 0.01), -1.0, 1.0)
|
| 222 |
+
return 0.5 + 0.5 * net_norm
|
| 223 |
+
|
| 224 |
+
|
| 225 |
+
def c_stable(load_window, k, mu_floor):
|
| 226 |
+
"""
|
| 227 |
+
Consumption stability via Coefficient of Variation.
|
| 228 |
+
CV = Ο / max(ΞΌ, mu_floor)
|
| 229 |
+
C_stable = 1 / (1 + k Γ CV)
|
| 230 |
+
"""
|
| 231 |
+
n = len(load_window)
|
| 232 |
+
if n < 2:
|
| 233 |
+
return 1.0
|
| 234 |
+
mu = sum(load_window) / n
|
| 235 |
+
if mu < 1e-6:
|
| 236 |
+
return 1.0
|
| 237 |
+
variance = sum((x - mu) ** 2 for x in load_window) / (n - 1)
|
| 238 |
+
sigma = math.sqrt(variance)
|
| 239 |
+
cv = sigma / max(mu, mu_floor)
|
| 240 |
+
return 1.0 / (1.0 + k * cv)
|
| 241 |
+
|
| 242 |
+
|
| 243 |
+
def v_dep(bat_window, fresh_window,
|
| 244 |
+
bat_pct_now, fresh_L_now,
|
| 245 |
+
fresh_cap_L, bat_crit_pct,
|
| 246 |
+
horizon_hr, v_floor):
|
| 247 |
+
"""
|
| 248 |
+
Depletion velocity modifier β (V_dep, ttc_hr).
|
| 249 |
+
|
| 250 |
+
Computes velocity of battery (% / hr) and fresh water (L / hr),
|
| 251 |
+
estimates time to critical threshold for each, takes the minimum,
|
| 252 |
+
then maps to a [v_floor, 1.0] suppression factor over horizon_hr.
|
| 253 |
+
"""
|
| 254 |
+
N = len(bat_window)
|
| 255 |
+
hrs = N / 60.0
|
| 256 |
+
INF = float("inf")
|
| 257 |
+
|
| 258 |
+
# Battery velocity (%/hr) β negative means depleting
|
| 259 |
+
v_bat = ((bat_pct_now - bat_window[0]) / hrs) if N >= 2 and hrs > 0 else 0.0
|
| 260 |
+
if v_bat < 0:
|
| 261 |
+
gap_bat = bat_pct_now - bat_crit_pct
|
| 262 |
+
ttc_bat = (gap_bat / max(abs(v_bat), 0.01)) if gap_bat > 0 else 0.0
|
| 263 |
+
else:
|
| 264 |
+
ttc_bat = INF
|
| 265 |
+
|
| 266 |
+
# Fresh water velocity (L/hr) β negative means depleting
|
| 267 |
+
crit_fresh_L = 0.15 * fresh_cap_L
|
| 268 |
+
v_fresh = ((fresh_L_now - fresh_window[0]) / hrs) if N >= 2 and hrs > 0 else 0.0
|
| 269 |
+
if v_fresh < 0:
|
| 270 |
+
gap_fresh = fresh_L_now - crit_fresh_L
|
| 271 |
+
ttc_fresh = (gap_fresh / max(abs(v_fresh), 0.1)) if gap_fresh > 0 else 0.0
|
| 272 |
+
else:
|
| 273 |
+
ttc_fresh = INF
|
| 274 |
+
|
| 275 |
+
ttc = min(ttc_bat, ttc_fresh)
|
| 276 |
+
ttc_hr = round(ttc, 4) if ttc != INF else 9999.0 # 9999 = "no depletion risk"
|
| 277 |
+
vd = clamp(ttc / horizon_hr, v_floor, 1.0) if ttc != INF else 1.0
|
| 278 |
+
return vd, ttc_hr
|
| 279 |
+
|
| 280 |
+
|
| 281 |
+
# βββββββββββββββββββββββββββββοΏ½οΏ½βββββββββββββββββββββββββββββββββββββββββββββββ
|
| 282 |
+
# MAIN CALCULATION LOOP
|
| 283 |
+
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 284 |
+
|
| 285 |
+
def calculate(power_path, water_path, cfg):
|
| 286 |
+
"""
|
| 287 |
+
Sequentially processes every 1-minute row.
|
| 288 |
+
Maintains rolling windows for multi-row computations.
|
| 289 |
+
Returns list of output dicts.
|
| 290 |
+
"""
|
| 291 |
+
rows = merge_rows(load_csv(power_path), load_csv(water_path))
|
| 292 |
+
|
| 293 |
+
N_energy = cfg["energy_window_min"]
|
| 294 |
+
N_stable = cfg["stable_window_min"]
|
| 295 |
+
N_velocity = cfg["velocity_window_min"]
|
| 296 |
+
warm_up = max(N_energy, N_velocity) # longest window = warm-up horizon
|
| 297 |
+
|
| 298 |
+
gen_win = deque(maxlen=N_energy) # Solar + Shore [kW]
|
| 299 |
+
load_win_e = deque(maxlen=N_energy) # total load [kW] β energy window
|
| 300 |
+
load_win_s = deque(maxlen=N_stable) # total load [kW] β stability window
|
| 301 |
+
bat_win = deque(maxlen=N_velocity) # battery % β velocity window
|
| 302 |
+
fresh_win = deque(maxlen=N_velocity) # fresh water L β velocity window
|
| 303 |
+
|
| 304 |
+
results = []
|
| 305 |
+
|
| 306 |
+
for i, row in enumerate(rows):
|
| 307 |
+
# ββ Parse ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 308 |
+
bat_pct = float(row["Battery_Level_Pct"])
|
| 309 |
+
fresh_L = float(row["FreshTank_Level_L"])
|
| 310 |
+
grey_L = float(row["GreyTank_Level_L"])
|
| 311 |
+
black_L = float(row["BlackTank_Level_L"])
|
| 312 |
+
solar_kw = float(row["Solar_Flow_kW"])
|
| 313 |
+
shore_kw = float(row["Shore_Flow_kW"])
|
| 314 |
+
total_load = sum(float(row[c]) for c in LOAD_COLS)
|
| 315 |
+
|
| 316 |
+
# ββ Feed rolling windows βββββββββββββββββββββββββββββββββββββββββββ
|
| 317 |
+
gen_win.append(solar_kw + shore_kw)
|
| 318 |
+
load_win_e.append(total_load)
|
| 319 |
+
load_win_s.append(total_load)
|
| 320 |
+
bat_win.append(bat_pct)
|
| 321 |
+
fresh_win.append(fresh_L)
|
| 322 |
+
|
| 323 |
+
# ββ Component scores βββββββββββββββββββββββββββββββββββββββββββββββ
|
| 324 |
+
sc_bat = c_bat(bat_pct, cfg["bat_crit_pct"], cfg["bat_warn_pct"])
|
| 325 |
+
|
| 326 |
+
sc_fresh = c_fresh(
|
| 327 |
+
fresh_L, cfg["fresh_cap_L"],
|
| 328 |
+
cfg["fresh_crit_pct"], cfg["fresh_warn_pct"]
|
| 329 |
+
)
|
| 330 |
+
|
| 331 |
+
sc_waste, sc_grey, sc_black = c_waste(
|
| 332 |
+
grey_L, black_L,
|
| 333 |
+
cfg["grey_cap_L"], cfg["black_cap_L"],
|
| 334 |
+
cfg["grey_penalty_start"], cfg["black_penalty_start"],
|
| 335 |
+
cfg["grey_weight_in_waste"], cfg["black_weight_in_waste"]
|
| 336 |
+
)
|
| 337 |
+
|
| 338 |
+
sc_energy = c_energy(gen_win, load_win_e, cfg["solar_cap_kW"])
|
| 339 |
+
|
| 340 |
+
sc_stable = c_stable(load_win_s, cfg["stable_k"], cfg["stable_mu_floor"])
|
| 341 |
+
|
| 342 |
+
# ββ Weighted sum βββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 343 |
+
si_raw = 10.0 * (
|
| 344 |
+
cfg["w_bat"] * sc_bat +
|
| 345 |
+
cfg["w_fresh"] * sc_fresh +
|
| 346 |
+
cfg["w_waste"] * sc_waste +
|
| 347 |
+
cfg["w_energy"] * sc_energy +
|
| 348 |
+
cfg["w_stable"] * sc_stable
|
| 349 |
+
)
|
| 350 |
+
si_raw = clamp(si_raw, 0.0, 10.0)
|
| 351 |
+
|
| 352 |
+
# ββ Depletion velocity modifier ββββββββββββββββββββββββββββββββββββ
|
| 353 |
+
vd, ttc_hr = v_dep(
|
| 354 |
+
bat_win, fresh_win,
|
| 355 |
+
bat_pct, fresh_L,
|
| 356 |
+
cfg["fresh_cap_L"], cfg["bat_crit_pct"],
|
| 357 |
+
cfg["velocity_horizon_hr"], cfg["velocity_min_factor"]
|
| 358 |
+
)
|
| 359 |
+
|
| 360 |
+
si_final = clamp(si_raw * vd, 0.0, 10.0)
|
| 361 |
+
|
| 362 |
+
results.append({
|
| 363 |
+
"Time": row["Time"],
|
| 364 |
+
"SI": round(si_final, 4),
|
| 365 |
+
"SI_raw": round(si_raw, 4),
|
| 366 |
+
"C_bat": round(sc_bat, 4),
|
| 367 |
+
"C_fresh": round(sc_fresh, 4),
|
| 368 |
+
"C_waste": round(sc_waste, 4),
|
| 369 |
+
"C_grey": round(sc_grey, 4),
|
| 370 |
+
"C_black": round(sc_black, 4),
|
| 371 |
+
"C_energy": round(sc_energy, 4),
|
| 372 |
+
"C_stable": round(sc_stable, 4),
|
| 373 |
+
"V_dep": round(vd, 4),
|
| 374 |
+
"ttc_hr": ttc_hr,
|
| 375 |
+
"band": band_label(si_final, cfg["bands"]),
|
| 376 |
+
"warm_up": "true" if i < warm_up else "false",
|
| 377 |
+
# Passthrough context columns
|
| 378 |
+
"Battery_Level_Pct": round(bat_pct, 2),
|
| 379 |
+
"FreshTank_Level_L": round(fresh_L, 2),
|
| 380 |
+
"GreyTank_Level_L": round(grey_L, 2),
|
| 381 |
+
"BlackTank_Level_L": round(black_L, 2),
|
| 382 |
+
})
|
| 383 |
+
|
| 384 |
+
return results
|
| 385 |
+
|
| 386 |
+
|
| 387 |
+
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 388 |
+
# SUMMARY REPORT
|
| 389 |
+
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 390 |
+
|
| 391 |
+
def print_summary(results, cfg):
|
| 392 |
+
warm = [r for r in results if r["warm_up"] == "false"] or results
|
| 393 |
+
|
| 394 |
+
si_vals = [r["SI"] for r in warm]
|
| 395 |
+
si_mean = statistics.mean(si_vals)
|
| 396 |
+
si_min = min(si_vals)
|
| 397 |
+
si_max = max(si_vals)
|
| 398 |
+
si_std = statistics.stdev(si_vals) if len(si_vals) > 1 else 0.0
|
| 399 |
+
|
| 400 |
+
band_counts = {}
|
| 401 |
+
for r in warm:
|
| 402 |
+
band_counts[r["band"]] = band_counts.get(r["band"], 0) + 1
|
| 403 |
+
|
| 404 |
+
worst = min(warm, key=lambda r: r["SI"])
|
| 405 |
+
best = max(warm, key=lambda r: r["SI"])
|
| 406 |
+
|
| 407 |
+
def cmean(key):
|
| 408 |
+
return round(statistics.mean(r[key] for r in warm), 3)
|
| 409 |
+
|
| 410 |
+
W = 62
|
| 411 |
+
sep = "β" * W
|
| 412 |
+
|
| 413 |
+
print(f"\n{'β' * W}")
|
| 414 |
+
print(f" STABILITY INDEX β SUMMARY REPORT")
|
| 415 |
+
print(f" Period : {results[0]['Time']} β {results[-1]['Time']}")
|
| 416 |
+
print(f" Rows : {len(results):,} | Warm-up excluded: {len(results)-len(warm):,}")
|
| 417 |
+
print(f"{'β' * W}")
|
| 418 |
+
|
| 419 |
+
print(f"\n OVERALL SI")
|
| 420 |
+
print(f" {sep}")
|
| 421 |
+
print(f" Mean : {si_mean:6.3f} ({band_label(si_mean, cfg['bands'])})")
|
| 422 |
+
print(f" Min : {si_min:6.3f} @ {worst['Time']} [{worst['band']}]")
|
| 423 |
+
print(f" Max : {si_max:6.3f} @ {best['Time']} [{best['band']}]")
|
| 424 |
+
print(f" Std : {si_std:6.3f}")
|
| 425 |
+
|
| 426 |
+
print(f"\n BAND DISTRIBUTION")
|
| 427 |
+
print(f" {sep}")
|
| 428 |
+
total = len(warm)
|
| 429 |
+
for b in ["Excellent", "Good", "Fair", "Poor", "Critical"]:
|
| 430 |
+
n = band_counts.get(b, 0)
|
| 431 |
+
pct = n / total * 100 if total else 0
|
| 432 |
+
bar = "β" * int(pct / 2)
|
| 433 |
+
print(f" {b:<12} {n:>5} min ({pct:5.1f}%) {bar}")
|
| 434 |
+
|
| 435 |
+
print(f"\n COMPONENT AVERAGES (0β1, higher = more stable)")
|
| 436 |
+
print(f" {sep}")
|
| 437 |
+
rows = [
|
| 438 |
+
("C_bat", "Battery SOC ", cfg["w_bat"]),
|
| 439 |
+
("C_fresh", "Fresh Water ", cfg["w_fresh"]),
|
| 440 |
+
("C_waste", "Waste Headroom ", cfg["w_waste"]),
|
| 441 |
+
("C_grey", " β³ Grey tank ", cfg["grey_weight_in_waste"] * cfg["w_waste"]),
|
| 442 |
+
("C_black", " β³ Black tank ", cfg["black_weight_in_waste"] * cfg["w_waste"]),
|
| 443 |
+
("C_energy", "Energy Balance ", cfg["w_energy"]),
|
| 444 |
+
("C_stable", "Cons. Stability", cfg["w_stable"]),
|
| 445 |
+
("V_dep", "Depl. Velocity ", None),
|
| 446 |
+
]
|
| 447 |
+
for key, label, weight in rows:
|
| 448 |
+
val = cmean(key)
|
| 449 |
+
bar = "β" * int(val * 20)
|
| 450 |
+
wstr = f"w={weight:.2f}" if weight is not None else "modifier"
|
| 451 |
+
print(f" {label} {val:.3f} {bar:<22} {wstr}")
|
| 452 |
+
|
| 453 |
+
# Identify consecutive critical/poor runs
|
| 454 |
+
crit = [r for r in warm if r["band"] in ("Critical", "Poor")]
|
| 455 |
+
if crit:
|
| 456 |
+
# Build index for consecutive-run detection
|
| 457 |
+
idx_map = {r["Time"]: i for i, r in enumerate(results)}
|
| 458 |
+
runs, run_start, prev_i = [], None, None
|
| 459 |
+
for r in crit:
|
| 460 |
+
ri = idx_map[r["Time"]]
|
| 461 |
+
if prev_i is None or ri != prev_i + 1:
|
| 462 |
+
if run_start is not None:
|
| 463 |
+
runs.append((run_start, results[prev_i]))
|
| 464 |
+
run_start = r
|
| 465 |
+
prev_i = ri
|
| 466 |
+
if run_start:
|
| 467 |
+
runs.append((run_start, results[prev_i]))
|
| 468 |
+
|
| 469 |
+
print(f"\n β POOR / CRITICAL EVENTS ({len(crit)} minutes across {len(runs)} run(s))")
|
| 470 |
+
print(f" {sep}")
|
| 471 |
+
for start, end in runs[:10]:
|
| 472 |
+
dur = idx_map[end["Time"]] - idx_map[start["Time"]] + 1
|
| 473 |
+
print(f" {start['Time']} SI={start['SI']:.2f} "
|
| 474 |
+
f"[{start['band']}] duration={dur} min "
|
| 475 |
+
f"bat={start['Battery_Level_Pct']}% "
|
| 476 |
+
f"fresh={start['FreshTank_Level_L']:.0f}L")
|
| 477 |
+
if len(runs) > 10:
|
| 478 |
+
print(f" β¦ and {len(runs)-10} more run(s)")
|
| 479 |
+
else:
|
| 480 |
+
print(f"\n β No Critical or Poor events detected.")
|
| 481 |
+
|
| 482 |
+
print(f"\n{'β' * W}\n")
|
| 483 |
+
|
| 484 |
+
|
| 485 |
+
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 486 |
+
# CSV WRITER
|
| 487 |
+
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 488 |
+
|
| 489 |
+
def write_csv(path, rows):
|
| 490 |
+
if not rows:
|
| 491 |
+
print(" No rows to write.")
|
| 492 |
+
return
|
| 493 |
+
Path(path).parent.mkdir(parents=True, exist_ok=True)
|
| 494 |
+
with open(path, "w", newline="") as f:
|
| 495 |
+
w = csv.DictWriter(f, fieldnames=rows[0].keys())
|
| 496 |
+
w.writeheader()
|
| 497 |
+
w.writerows(rows)
|
| 498 |
+
print(f" Wrote {len(rows):,} rows β {path}")
|
| 499 |
+
|
| 500 |
+
|
| 501 |
+
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 502 |
+
# ENTRY POINT
|
| 503 |
+
# βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
|
| 504 |
+
|
| 505 |
+
def main():
|
| 506 |
+
parser = argparse.ArgumentParser(
|
| 507 |
+
description="EV Camper Stability Index Engine",
|
| 508 |
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
| 509 |
+
epilog="""
|
| 510 |
+
Examples:
|
| 511 |
+
python stability_index.py --summary
|
| 512 |
+
python stability_index.py --power_dir data/power --water_dir data/water
|
| 513 |
+
python stability_index.py --config si_config.json --out scores/si.csv --summary
|
| 514 |
+
python stability_index.py --w_bat 0.40 --w_fresh 0.20 --w_energy 0.20 --w_waste 0.10 --w_stable 0.10
|
| 515 |
+
"""
|
| 516 |
+
)
|
| 517 |
+
# Paths
|
| 518 |
+
parser.add_argument("--power_dir", default="output/power",
|
| 519 |
+
help="Directory containing 1MIN.csv (default: output/power)")
|
| 520 |
+
parser.add_argument("--water_dir", default="output/water",
|
| 521 |
+
help="Directory containing 1MIN.csv (default: output/water)")
|
| 522 |
+
parser.add_argument("--out", default="output/stability_index.csv",
|
| 523 |
+
help="Output CSV path (default: output/stability_index.csv)")
|
| 524 |
+
parser.add_argument("--config", default=None,
|
| 525 |
+
help="JSON config file to override any DEFAULT_CONFIG value")
|
| 526 |
+
|
| 527 |
+
# Inline weight overrides
|
| 528 |
+
parser.add_argument("--w_bat", type=float, default=None, metavar="W",
|
| 529 |
+
help="Battery SOC weight (overrides config)")
|
| 530 |
+
parser.add_argument("--w_fresh", type=float, default=None, metavar="W")
|
| 531 |
+
parser.add_argument("--w_waste", type=float, default=None, metavar="W")
|
| 532 |
+
parser.add_argument("--w_energy", type=float, default=None, metavar="W")
|
| 533 |
+
parser.add_argument("--w_stable", type=float, default=None, metavar="W")
|
| 534 |
+
|
| 535 |
+
# Other inline overrides
|
| 536 |
+
parser.add_argument("--solar_cap_kW", type=float, default=None)
|
| 537 |
+
parser.add_argument("--energy_window_min", type=int, default=None)
|
| 538 |
+
parser.add_argument("--stable_window_min", type=int, default=None)
|
| 539 |
+
parser.add_argument("--velocity_horizon_hr", type=float, default=None)
|
| 540 |
+
parser.add_argument("--fresh_cap_L", type=float, default=None)
|
| 541 |
+
parser.add_argument("--grey_cap_L", type=float, default=None)
|
| 542 |
+
parser.add_argument("--black_cap_L", type=float, default=None)
|
| 543 |
+
|
| 544 |
+
parser.add_argument("--summary", action="store_true",
|
| 545 |
+
help="Print a human-readable summary report to stdout")
|
| 546 |
+
|
| 547 |
+
args = parser.parse_args()
|
| 548 |
+
|
| 549 |
+
# Build config with optional file + CLI overrides
|
| 550 |
+
cfg = load_config(args.config)
|
| 551 |
+
for key in ["w_bat", "w_fresh", "w_waste", "w_energy", "w_stable",
|
| 552 |
+
"solar_cap_kW", "energy_window_min", "stable_window_min",
|
| 553 |
+
"velocity_horizon_hr", "fresh_cap_L", "grey_cap_L", "black_cap_L"]:
|
| 554 |
+
val = getattr(args, key, None)
|
| 555 |
+
if val is not None:
|
| 556 |
+
cfg[key] = val
|
| 557 |
+
|
| 558 |
+
total_w = cfg["w_bat"] + cfg["w_fresh"] + cfg["w_waste"] + cfg["w_energy"] + cfg["w_stable"]
|
| 559 |
+
if abs(total_w - 1.0) > 1e-4:
|
| 560 |
+
raise SystemExit(
|
| 561 |
+
f"ERROR: weights must sum to 1.0 (got {total_w:.4f})\n"
|
| 562 |
+
f" bat={cfg['w_bat']} fresh={cfg['w_fresh']} waste={cfg['w_waste']} "
|
| 563 |
+
f"energy={cfg['w_energy']} stable={cfg['w_stable']}"
|
| 564 |
+
)
|
| 565 |
+
|
| 566 |
+
power_path = str(Path(args.power_dir) / "1MIN.csv")
|
| 567 |
+
water_path = str(Path(args.water_dir) / "1MIN.csv")
|
| 568 |
+
|
| 569 |
+
print(f"\n{'='*62}")
|
| 570 |
+
print(f" Stability Index Engine v1.0")
|
| 571 |
+
print(f"{'='*62}")
|
| 572 |
+
print(f" Power : {power_path}")
|
| 573 |
+
print(f" Water : {water_path}")
|
| 574 |
+
print(f" Weights: bat={cfg['w_bat']} fresh={cfg['w_fresh']} "
|
| 575 |
+
f"waste={cfg['w_waste']} energy={cfg['w_energy']} stable={cfg['w_stable']}")
|
| 576 |
+
print(f" Windows: energy={cfg['energy_window_min']}min "
|
| 577 |
+
f"stable={cfg['stable_window_min']}min "
|
| 578 |
+
f"velocity={cfg['velocity_window_min']}min")
|
| 579 |
+
print()
|
| 580 |
+
|
| 581 |
+
print(" Calculating...")
|
| 582 |
+
results = calculate(power_path, water_path, cfg)
|
| 583 |
+
|
| 584 |
+
write_csv(args.out, results)
|
| 585 |
+
|
| 586 |
+
if args.summary:
|
| 587 |
+
print_summary(results, cfg)
|
| 588 |
+
|
| 589 |
+
print(f" Done.\n")
|
| 590 |
+
|
| 591 |
+
|
| 592 |
+
if __name__ == "__main__":
|
| 593 |
+
main()
|
static/index.html
ADDED
|
@@ -0,0 +1,466 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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>EV Camper β Energy Dashboard</title>
|
| 7 |
+
<script src="https://cdn.jsdelivr.net/npm/vue@3/dist/vue.global.prod.js"></script>
|
| 8 |
+
<script src="https://cdn.jsdelivr.net/npm/chart.js@4"></script>
|
| 9 |
+
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-annotation@3"></script>
|
| 10 |
+
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@300;400;500;600;700&family=DM+Sans:opsz,wght@9..40,300;9..40,400;9..40,500;9..40,600;9..40,700&display=swap" rel="stylesheet">
|
| 11 |
+
<style>
|
| 12 |
+
*{margin:0;padding:0;box-sizing:border-box}
|
| 13 |
+
:root{
|
| 14 |
+
--bg-0:#060a10;--bg-1:#0c1118;--bg-2:#121a24;--bg-3:#182230;
|
| 15 |
+
--border:#1c2838;--border-hi:#283848;
|
| 16 |
+
--t1:#e8edf4;--t2:#8a9bb0;--t3:#506070;
|
| 17 |
+
--accent:#2ee8a8;--accent-d:#1cba80;--accent-g:rgba(46,232,168,.1);
|
| 18 |
+
--solar:#ffb020;--solar-g:rgba(255,176,32,.08);
|
| 19 |
+
--batt:#4890ff;--batt-g:rgba(72,144,255,.08);
|
| 20 |
+
--shore:#b48afa;--hvac:#ff5050;--cook:#ff8830;
|
| 21 |
+
--fresh:#18d4e8;--grey-t:#7888a0;--black-t:#585858;
|
| 22 |
+
--danger:#ff4040;--warn:#ffa020;--ok:#30e090;
|
| 23 |
+
--mono:'JetBrains Mono',monospace;--sans:'DM Sans',sans-serif;
|
| 24 |
+
}
|
| 25 |
+
html,body{height:100%;background:var(--bg-0);color:var(--t1);font-family:var(--sans)}
|
| 26 |
+
::-webkit-scrollbar{width:5px}::-webkit-scrollbar-track{background:var(--bg-0)}
|
| 27 |
+
::-webkit-scrollbar-thumb{background:var(--border-hi);border-radius:3px}
|
| 28 |
+
#app{display:flex;height:100vh;overflow:hidden}
|
| 29 |
+
.sb{width:208px;background:var(--bg-1);border-right:1px solid var(--border);display:flex;flex-direction:column;flex-shrink:0}
|
| 30 |
+
.sb-logo{padding:18px 16px;border-bottom:1px solid var(--border)}
|
| 31 |
+
.sb-logo h1{font:600 13px/1 var(--mono);letter-spacing:1.8px;color:var(--accent);text-transform:uppercase}
|
| 32 |
+
.sb-logo p{font:11px var(--mono);color:var(--t3);margin-top:5px}
|
| 33 |
+
.sb-nav{flex:1;padding:10px 0;overflow-y:auto}
|
| 34 |
+
.sb-sec{padding:10px 16px 4px;font:500 9px/1 var(--mono);letter-spacing:1.8px;text-transform:uppercase;color:var(--t3)}
|
| 35 |
+
.ni{display:flex;align-items:center;gap:9px;padding:8px 16px;cursor:pointer;transition:.12s;color:var(--t2);font:500 12.5px var(--sans);border-left:2px solid transparent;user-select:none}
|
| 36 |
+
.ni:hover{background:var(--bg-3);color:var(--t1)}
|
| 37 |
+
.ni.on{color:var(--accent);border-left-color:var(--accent);background:var(--accent-g)}
|
| 38 |
+
.ni svg{width:15px;height:15px;flex-shrink:0;opacity:.65}.ni.on svg{opacity:1}
|
| 39 |
+
.sb-ft{padding:12px 16px;border-top:1px solid var(--border);font:11px var(--mono);color:var(--t3)}
|
| 40 |
+
.mn{flex:1;overflow-y:auto;overflow-x:hidden}
|
| 41 |
+
.ph{padding:22px 28px 0;display:flex;align-items:flex-end;justify-content:space-between;gap:16px;flex-wrap:wrap}
|
| 42 |
+
.ph h2{font:600 20px/1.2 var(--sans);letter-spacing:-.3px}
|
| 43 |
+
.ph .sub{font:13px var(--sans);color:var(--t2);margin-top:3px}
|
| 44 |
+
.badges{display:flex;gap:6px;flex-wrap:wrap}
|
| 45 |
+
.bdg{display:inline-flex;align-items:center;gap:4px;padding:3px 9px;border-radius:5px;font:500 10px var(--mono);border:1px solid var(--border)}
|
| 46 |
+
.bdg-g{color:var(--accent);border-color:var(--accent-d);background:var(--accent-g)}
|
| 47 |
+
.bdg-s{color:var(--solar);border-color:#b07810;background:var(--solar-g)}
|
| 48 |
+
.pc{padding:18px 28px 48px}
|
| 49 |
+
.g{display:grid;gap:14px}
|
| 50 |
+
.g4{grid-template-columns:repeat(4,1fr)}.g3{grid-template-columns:repeat(3,1fr)}
|
| 51 |
+
.g2{grid-template-columns:repeat(2,1fr)}.g21{grid-template-columns:2fr 1fr}
|
| 52 |
+
.g12{grid-template-columns:1fr 2fr}.g1{grid-template-columns:1fr}
|
| 53 |
+
.s2{grid-column:span 2}.s3{grid-column:span 3}.s4{grid-column:span 4}
|
| 54 |
+
.cd{background:var(--bg-2);border:1px solid var(--border);border-radius:10px;overflow:hidden}
|
| 55 |
+
.cd-h{padding:13px 16px 0;display:flex;justify-content:space-between;align-items:center}
|
| 56 |
+
.cd-t{font:500 10.5px/1 var(--mono);letter-spacing:1.2px;text-transform:uppercase;color:var(--t3)}
|
| 57 |
+
.cd-b{padding:12px 16px 16px;position:relative}.cd-b canvas{width:100%!important}
|
| 58 |
+
.kpi{padding:16px}
|
| 59 |
+
.kpi-l{font:10px var(--mono);letter-spacing:1.4px;text-transform:uppercase;color:var(--t3);margin-bottom:6px}
|
| 60 |
+
.kpi-v{font:700 26px/1 var(--mono);letter-spacing:-1px}
|
| 61 |
+
.kpi-s{font:11px var(--mono);color:var(--t2);margin-top:5px}
|
| 62 |
+
.kpi-v.grn{color:var(--accent)}.kpi-v.sol{color:var(--solar)}.kpi-v.blu{color:var(--batt)}
|
| 63 |
+
.kpi-v.cyn{color:var(--fresh)}.kpi-v.red{color:var(--hvac)}.kpi-v.prp{color:var(--shore)}
|
| 64 |
+
.kpi-bar{height:3px;border-radius:2px;background:var(--bg-0);margin-top:8px;overflow:hidden}
|
| 65 |
+
.kpi-bar-f{height:100%;border-radius:2px;transition:width .6s ease}
|
| 66 |
+
.gauge-w{display:flex;align-items:center;justify-content:center;padding:16px}
|
| 67 |
+
.gauge-r{position:relative;width:140px;height:140px}
|
| 68 |
+
.gauge-r svg{transform:rotate(-90deg)}.gauge-r circle{fill:none;stroke-linecap:round}
|
| 69 |
+
.gauge-r .trk{stroke:var(--border)}.gauge-r .fil{transition:stroke-dashoffset .7s ease}
|
| 70 |
+
.gauge-c{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center}
|
| 71 |
+
.gauge-p{font:700 28px/1 var(--mono)}
|
| 72 |
+
.gauge-lb{font:9px var(--mono);letter-spacing:1.2px;text-transform:uppercase;color:var(--t3);margin-top:4px}
|
| 73 |
+
.tk{display:flex;align-items:center;gap:10px;padding:6px 0}
|
| 74 |
+
.tk-l{width:50px;font:10px var(--mono);color:var(--t2);text-transform:uppercase}
|
| 75 |
+
.tk-bg{flex:1;height:18px;background:var(--bg-0);border-radius:3px;overflow:hidden;position:relative}
|
| 76 |
+
.tk-f{height:100%;border-radius:3px;transition:width .5s ease;display:flex;align-items:center;justify-content:flex-end;padding-right:6px;font:600 9px var(--mono);color:rgba(255,255,255,.85);min-width:30px}
|
| 77 |
+
.tk-v{width:55px;text-align:right;font:11px var(--mono);color:var(--t2)}
|
| 78 |
+
.dtabs{display:flex;gap:3px;margin-bottom:14px;flex-wrap:wrap}
|
| 79 |
+
.dtab{padding:5px 12px;border-radius:5px;font:11px var(--mono);cursor:pointer;border:1px solid var(--border);background:transparent;color:var(--t2);transition:.12s}
|
| 80 |
+
.dtab:hover{border-color:var(--border-hi);color:var(--t1)}
|
| 81 |
+
.dtab.on{border-color:var(--accent-d);color:var(--accent);background:var(--accent-g)}
|
| 82 |
+
.tb{width:100%;border-collapse:collapse;font-size:11px}
|
| 83 |
+
.tb th{text-align:left;padding:7px 10px;font:500 9px var(--mono);text-transform:uppercase;letter-spacing:1px;color:var(--t3);border-bottom:1px solid var(--border)}
|
| 84 |
+
.tb td{padding:6px 10px;border-bottom:1px solid var(--border);color:var(--t2);font:11px var(--mono)}
|
| 85 |
+
.tb tr:hover td{background:var(--bg-3);color:var(--t1)}
|
| 86 |
+
.tb-cat{padding:8px 10px;font:600 10px var(--mono);letter-spacing:1.5px;text-transform:uppercase;color:var(--accent);background:var(--accent-g);border-bottom:1px solid var(--border)}
|
| 87 |
+
.donut-w{max-width:220px;margin:0 auto}
|
| 88 |
+
.insight{display:flex;align-items:flex-start;gap:8px;padding:10px 12px;border-radius:6px;background:var(--bg-3);border-left:3px solid var(--accent);margin-bottom:12px;font:12px/1.5 var(--sans);color:var(--t2)}
|
| 89 |
+
.insight.warn{border-left-color:var(--warn)}.insight.danger{border-left-color:var(--danger)}
|
| 90 |
+
.insight b{color:var(--t1);font-weight:600}
|
| 91 |
+
.insight-icon{font-size:14px;flex-shrink:0;margin-top:1px}
|
| 92 |
+
.form-group{margin-bottom:14px}
|
| 93 |
+
.form-label{display:block;font:500 10px var(--mono);letter-spacing:1px;text-transform:uppercase;color:var(--t3);margin-bottom:5px}
|
| 94 |
+
.form-select,.form-input{width:100%;padding:8px 10px;border-radius:6px;border:1px solid var(--border);background:var(--bg-1);color:var(--t1);font:13px var(--sans);outline:none;transition:.15s}
|
| 95 |
+
.form-select:focus,.form-input:focus{border-color:var(--accent)}
|
| 96 |
+
.form-select option{background:var(--bg-1)}
|
| 97 |
+
.form-row{display:flex;gap:12px}.form-row>*{flex:1}
|
| 98 |
+
.btn{padding:10px 20px;border-radius:7px;border:none;cursor:pointer;font:600 12px var(--sans);transition:.15s}
|
| 99 |
+
.btn-primary{background:var(--accent);color:var(--bg-0)}.btn-primary:hover{background:var(--accent-d)}
|
| 100 |
+
.btn-primary:disabled{opacity:.5;cursor:wait}
|
| 101 |
+
.gen-status{margin-top:10px;font:12px var(--mono);color:var(--t2);min-height:20px}
|
| 102 |
+
.gen-status.ok{color:var(--accent)}.gen-status.err{color:var(--danger)}
|
| 103 |
+
.ld{display:flex;align-items:center;justify-content:center;height:200px;color:var(--t3);font:12px var(--mono);letter-spacing:1px}
|
| 104 |
+
.pulse{animation:pulse 1.2s ease infinite}
|
| 105 |
+
@keyframes pulse{0%,100%{opacity:.3}50%{opacity:1}}
|
| 106 |
+
@media(max-width:900px){
|
| 107 |
+
.sb{width:54px}.sb-logo p,.ni span,.sb-ft,.sb-sec{display:none}
|
| 108 |
+
.sb-logo h1{font-size:10px;text-align:center}.ni{justify-content:center;padding:10px}
|
| 109 |
+
.ph,.pc{padding-left:14px;padding-right:14px}
|
| 110 |
+
.g4,.g3{grid-template-columns:repeat(2,1fr)}
|
| 111 |
+
.g2,.g12,.g21{grid-template-columns:1fr}
|
| 112 |
+
.s2,.s3,.s4{grid-column:span 1}
|
| 113 |
+
}
|
| 114 |
+
</style>
|
| 115 |
+
</head>
|
| 116 |
+
<body>
|
| 117 |
+
<div id="app">
|
| 118 |
+
<aside class="sb">
|
| 119 |
+
<div class="sb-logo"><h1>β‘ EV Camp</h1><p>Resource Monitor</p></div>
|
| 120 |
+
<nav class="sb-nav">
|
| 121 |
+
<div class="sb-sec">Dashboard</div>
|
| 122 |
+
<div class="ni" :class="{on:pg==='overview'}" @click="go('overview')">
|
| 123 |
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/><rect x="14" y="14" width="7" height="7" rx="1"/></svg><span>Overview</span>
|
| 124 |
+
</div>
|
| 125 |
+
<div class="ni" :class="{on:pg==='power'}" @click="go('power')">
|
| 126 |
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M13 2L3 14h9l-1 8 10-12h-9l1-8z"/></svg><span>Power</span>
|
| 127 |
+
</div>
|
| 128 |
+
<div class="ni" :class="{on:pg==='water'}" @click="go('water')">
|
| 129 |
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2.69l5.66 5.66a8 8 0 11-11.31 0z"/></svg><span>Water</span>
|
| 130 |
+
</div>
|
| 131 |
+
<div class="ni" :class="{on:pg==='budget'}" @click="go('budget')">
|
| 132 |
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 12V7H5a2 2 0 010-4h14v4"/><path d="M3 5v14a2 2 0 002 2h16v-5"/><path d="M18 12a2 2 0 100 4 2 2 0 000-4z"/></svg><span>Budget</span>
|
| 133 |
+
</div>
|
| 134 |
+
<div class="ni" :class="{on:pg==='components'}" @click="go('components')">
|
| 135 |
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="4" y="4" width="16" height="16" rx="2"/><path d="M9 1v3M15 1v3M9 20v3M15 20v3M20 9h3M20 14h3M1 9h3M1 14h3"/></svg><span>Components</span>
|
| 136 |
+
</div>
|
| 137 |
+
<div class="sb-sec" style="margin-top:8px">Settings</div>
|
| 138 |
+
<div class="ni" :class="{on:pg==='generate'}" @click="go('generate')">
|
| 139 |
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 00.33 1.82l.06.06a2 2 0 01-2.83 2.83l-.06-.06a1.65 1.65 0 00-1.82-.33 1.65 1.65 0 00-1 1.51V21a2 2 0 01-4 0v-.09A1.65 1.65 0 009 19.4a1.65 1.65 0 00-1.82.33l-.06.06a2 2 0 01-2.83-2.83l.06-.06A1.65 1.65 0 004.68 15a1.65 1.65 0 00-1.51-1H3a2 2 0 010-4h.09A1.65 1.65 0 004.6 9a1.65 1.65 0 00-.33-1.82l-.06-.06a2 2 0 012.83-2.83l.06.06A1.65 1.65 0 009 4.68a1.65 1.65 0 001-1.51V3a2 2 0 014 0v.09a1.65 1.65 0 001 1.51 1.65 1.65 0 001.82-.33l.06-.06a2 2 0 012.83 2.83l-.06.06A1.65 1.65 0 0019.4 9a1.65 1.65 0 001.51 1H21a2 2 0 010 4h-.09a1.65 1.65 0 00-1.51 1z"/></svg><span>Generate Data</span>
|
| 140 |
+
</div>
|
| 141 |
+
</nav>
|
| 142 |
+
<div class="sb-ft">v1.0 Β· {{cfg?.inputs?.params?.user_type?.value||'...'}}</div>
|
| 143 |
+
</aside>
|
| 144 |
+
|
| 145 |
+
<main class="mn">
|
| 146 |
+
<!-- OVERVIEW -->
|
| 147 |
+
<template v-if="pg==='overview'">
|
| 148 |
+
<div class="ph">
|
| 149 |
+
<div><h2>Trip Overview</h2><div class="sub">{{S.trip_days}}-day trip Β· {{cfg?.inputs?.params?.num_people?.value}} occupants Β· {{cfg?.inputs?.params?.temperature?.value}}</div></div>
|
| 150 |
+
<div class="badges">
|
| 151 |
+
<span class="bdg bdg-s">β {{cfg?.inputs?.params?.sunlight?.value}}</span>
|
| 152 |
+
<span class="bdg bdg-g">{{S.self_sufficiency_pct}}% Solar Coverage</span>
|
| 153 |
+
</div>
|
| 154 |
+
</div>
|
| 155 |
+
<div class="pc">
|
| 156 |
+
<div v-if="S.self_sufficiency_pct>=100" class="insight"><span class="insight-icon">π</span><div>Solar generation <b>exceeds</b> total consumption by <b>{{Math.round(S.total_solar_kwh-S.total_consumption_kwh)}} kWh</b>. Fully self-sufficient β no shore power needed.</div></div>
|
| 157 |
+
<div v-else class="insight warn"><span class="insight-icon">β οΈ</span><div>Solar covers only <b>{{S.self_sufficiency_pct}}%</b> of demand. Consider reducing HVAC usage or connecting shore power.</div></div>
|
| 158 |
+
<div v-if="(S.water?.fresh_remaining_pct||100)<30" class="insight danger"><span class="insight-icon">π§</span><div>Fresh water at <b>{{Math.round(S.water.fresh_remaining_pct)}}%</b>. At ~{{Math.round(S.water.total_fresh_used_L/S.trip_days)}} L/day, roughly <b>{{(S.water.fresh_remaining_L/(S.water.total_fresh_used_L/S.trip_days)).toFixed(1)}}</b> days remain.</div></div>
|
| 159 |
+
<div class="g g4" style="margin-bottom:14px">
|
| 160 |
+
<div class="cd kpi"><div class="kpi-l">Solar Generated</div><div class="kpi-v sol">{{S.total_solar_kwh}}</div><div class="kpi-s">kWh total Β· {{rd(S.total_solar_kwh/S.trip_days)}}/day</div><div class="kpi-bar"><div class="kpi-bar-f" style="width:100%;background:var(--solar)"></div></div></div>
|
| 161 |
+
<div class="cd kpi"><div class="kpi-l">Total Consumed</div><div class="kpi-v red">{{S.total_consumption_kwh}}</div><div class="kpi-s">kWh total Β· {{rd(S.total_consumption_kwh/S.trip_days)}}/day</div><div class="kpi-bar"><div class="kpi-bar-f" :style="{width:Math.min(100,S.total_consumption_kwh/Math.max(S.total_solar_kwh,.1)*100)+'%',background:'var(--hvac)'}"></div></div></div>
|
| 162 |
+
<div class="cd kpi"><div class="kpi-l">Battery Now</div><div class="kpi-v blu">{{S.battery?.current_pct}}%</div><div class="kpi-s">min {{S.battery?.min_pct}}% Β· avg {{S.battery?.avg_pct}}%</div><div class="kpi-bar"><div class="kpi-bar-f" :style="{width:(S.battery?.current_pct||0)+'%',background:battCol}"></div></div></div>
|
| 163 |
+
<div class="cd kpi"><div class="kpi-l">Fresh Water Left</div><div class="kpi-v cyn">{{Math.round(S.water?.fresh_remaining_pct||0)}}%</div><div class="kpi-s">{{fL(S.water?.fresh_remaining_L)}} L remaining</div><div class="kpi-bar"><div class="kpi-bar-f" :style="{width:(S.water?.fresh_remaining_pct||0)+'%',background:'var(--fresh)'}"></div></div></div>
|
| 164 |
+
</div>
|
| 165 |
+
<div class="g g21" style="margin-bottom:14px">
|
| 166 |
+
<div class="cd"><div class="cd-h"><span class="cd-t">Daily Energy Balance</span><span class="cd-t" style="color:var(--t2)">kWh/day</span></div><div class="cd-b"><canvas id="ov-energy" height="220"></canvas></div></div>
|
| 167 |
+
<div class="cd"><div class="cd-h"><span class="cd-t">System Status</span></div><div class="cd-b">
|
| 168 |
+
<div class="gauge-w"><div class="gauge-r"><svg viewBox="0 0 140 140" width="140" height="140"><circle cx="70" cy="70" r="58" class="trk" stroke-width="9"/><circle cx="70" cy="70" r="58" class="fil" stroke-width="9" :stroke="battCol" stroke-dasharray="364.4" :stroke-dashoffset="364.4*(1-(S.battery?.current_pct||0)/100)"/></svg><div class="gauge-c"><div class="gauge-p" :style="{color:battCol}">{{S.battery?.current_pct||0}}%</div><div class="gauge-lb">Battery SOC</div></div></div></div>
|
| 169 |
+
<div style="padding:0 2px">
|
| 170 |
+
<div class="tk"><span class="tk-l" style="color:var(--fresh)">Fresh</span><div class="tk-bg"><div class="tk-f" :style="{width:Math.max(8,S.water?.fresh_remaining_pct||0)+'%',background:'var(--fresh)'}">{{Math.round(S.water?.fresh_remaining_pct||0)}}%</div></div><span class="tk-v">{{fL(S.water?.fresh_remaining_L)}}L</span></div>
|
| 171 |
+
<div class="tk"><span class="tk-l" style="color:var(--grey-t)">Grey</span><div class="tk-bg"><div class="tk-f" :style="{width:Math.max(8,S.water?.grey_level_pct||0)+'%',background:'var(--grey-t)'}">{{Math.round(S.water?.grey_level_pct||0)}}%</div></div><span class="tk-v">{{fL(S.water?.grey_level_L)}}L</span></div>
|
| 172 |
+
<div class="tk"><span class="tk-l" style="color:var(--black-t)">Black</span><div class="tk-bg"><div class="tk-f" :style="{width:Math.max(8,S.water?.black_level_pct||0)+'%',background:'var(--black-t)'}">{{Math.round(S.water?.black_level_pct||0)}}%</div></div><span class="tk-v">{{fL(S.water?.black_level_L)}}L</span></div>
|
| 173 |
+
</div>
|
| 174 |
+
</div></div>
|
| 175 |
+
</div>
|
| 176 |
+
<div class="g g2">
|
| 177 |
+
<div class="cd"><div class="cd-h"><span class="cd-t">Consumption by Circuit</span><span class="cd-t" style="color:var(--t2)">kWh</span></div><div class="cd-b"><div class="donut-w"><canvas id="ov-donut" height="220"></canvas></div></div></div>
|
| 178 |
+
<div class="cd"><div class="cd-h"><span class="cd-t">Daily Breakdown</span></div><div class="cd-b"><table class="tb"><thead><tr><th>Day</th><th>Solar</th><th>Load</th><th>Net</th><th>Batt</th><th>Water</th></tr></thead><tbody><tr v-for="d in S.daily_breakdown||[]" :key="d.day"><td>Day {{d.day}}</td><td style="color:var(--solar)">{{d.solar_kwh}}</td><td style="color:var(--hvac)">{{d.consumption_kwh}}</td><td :style="{color:d.solar_kwh>=d.consumption_kwh?'var(--accent)':'var(--danger)'}">{{rd(d.solar_kwh-d.consumption_kwh)>0?'+':''}}{{rd(d.solar_kwh-d.consumption_kwh)}}</td><td :style="{color:d.battery_end_pct>40?'var(--accent)':'var(--danger)'}">{{d.battery_end_pct}}%</td><td style="color:var(--fresh)">{{d.fresh_used_L}}L</td></tr></tbody></table></div></div>
|
| 179 |
+
</div>
|
| 180 |
+
</div>
|
| 181 |
+
</template>
|
| 182 |
+
|
| 183 |
+
<!-- POWER -->
|
| 184 |
+
<template v-if="pg==='power'">
|
| 185 |
+
<div class="ph"><div><h2>Power Analytics</h2><div class="sub">Generation, consumption & battery analysis</div></div><div class="badges"><span class="bdg bdg-s">Avg Solar: {{rd(S.total_solar_kwh/S.trip_days)}} kWh/day</span></div></div>
|
| 186 |
+
<div class="pc">
|
| 187 |
+
<div class="dtabs"><div class="dtab" :class="{on:pDay===0}" @click="setPDay(0)">All Days</div><div class="dtab" v-for="d in S.trip_days" :key="d" :class="{on:pDay===d}" @click="setPDay(d)">Day {{d}}</div></div>
|
| 188 |
+
<div v-if="pDay>0&&pDayInsight" class="insight"><span class="insight-icon">π</span><div v-html="pDayInsight"></div></div>
|
| 189 |
+
<div class="g g1" style="margin-bottom:14px"><div class="cd"><div class="cd-h"><span class="cd-t">Solar Generation vs Total Load</span><span class="cd-t" style="color:var(--t2)">{{pDay?'Day '+pDay:'All'}} Β· 15-min kW</span></div><div class="cd-b"><canvas id="pw-solar" height="200" data-height="200"></canvas></div></div></div>
|
| 190 |
+
<div class="g g2" style="margin-bottom:14px">
|
| 191 |
+
<div class="cd"><div class="cd-h"><span class="cd-t">Battery State of Charge</span><span class="cd-t" style="color:var(--t2)">%</span></div><div class="cd-b"><canvas id="pw-batt" height="200" data-height="200"></canvas></div></div>
|
| 192 |
+
<div class="cd"><div class="cd-h"><span class="cd-t">Avg Hourly Load Profile</span><span class="cd-t" style="color:var(--t2)">kWh by circuit</span></div><div class="cd-b"><canvas id="pw-hourly" height="200" data-height="200"></canvas></div></div>
|
| 193 |
+
</div>
|
| 194 |
+
<div class="g g2">
|
| 195 |
+
<div class="cd"><div class="cd-h"><span class="cd-t">Circuit Breakdown (Hourly)</span><span class="cd-t" style="color:var(--t2)">Stacked kWh</span></div><div class="cd-b"><canvas id="pw-stack" height="220" data-height="220"></canvas></div></div>
|
| 196 |
+
<div class="cd"><div class="cd-h"><span class="cd-t">Energy Source Mix</span><span class="cd-t" style="color:var(--t2)">Solar / Battery / Shore</span></div><div class="cd-b"><canvas id="pw-source" height="220" data-height="220"></canvas></div></div>
|
| 197 |
+
</div>
|
| 198 |
+
</div>
|
| 199 |
+
</template>
|
| 200 |
+
|
| 201 |
+
<!-- WATER -->
|
| 202 |
+
<template v-if="pg==='water'">
|
| 203 |
+
<div class="ph"><div><h2>Water Management</h2><div class="sub">Tank levels, flow rates & usage patterns</div></div></div>
|
| 204 |
+
<div class="pc">
|
| 205 |
+
<div v-if="(S.water?.grey_level_pct||0)>80" class="insight warn"><span class="insight-icon">πΏ</span><div>Grey tank at <b>{{Math.round(S.water.grey_level_pct)}}%</b>. Consider dumping soon.</div></div>
|
| 206 |
+
<div class="g g4" style="margin-bottom:14px">
|
| 207 |
+
<div class="cd kpi"><div class="kpi-l">Total Fresh Used</div><div class="kpi-v cyn">{{fL(S.water?.total_fresh_used_L)}}</div><div class="kpi-s">litres Β· {{fL((S.water?.total_fresh_used_L||0)/S.trip_days)}}/day</div></div>
|
| 208 |
+
<div class="cd kpi"><div class="kpi-l">Fresh Remaining</div><div class="kpi-v cyn">{{Math.round(S.water?.fresh_remaining_pct||0)}}%</div><div class="kpi-s">{{fL(S.water?.fresh_remaining_L)}} L</div><div class="kpi-bar"><div class="kpi-bar-f" :style="{width:(S.water?.fresh_remaining_pct||0)+'%',background:'var(--fresh)'}"></div></div></div>
|
| 209 |
+
<div class="cd kpi"><div class="kpi-l">Grey Tank</div><div class="kpi-v" style="color:var(--grey-t)">{{Math.round(S.water?.grey_level_pct||0)}}%</div><div class="kpi-s">{{fL(S.water?.grey_level_L)}} L</div><div class="kpi-bar"><div class="kpi-bar-f" :style="{width:(S.water?.grey_level_pct||0)+'%',background:'var(--grey-t)'}"></div></div></div>
|
| 210 |
+
<div class="cd kpi"><div class="kpi-l">Black Tank</div><div class="kpi-v" style="color:var(--black-t)">{{Math.round(S.water?.black_level_pct||0)}}%</div><div class="kpi-s">{{fL(S.water?.black_level_L)}} L</div><div class="kpi-bar"><div class="kpi-bar-f" :style="{width:(S.water?.black_level_pct||0)+'%',background:'var(--black-t)'}"></div></div></div>
|
| 211 |
+
</div>
|
| 212 |
+
<div class="g g1" style="margin-bottom:14px"><div class="cd"><div class="cd-h"><span class="cd-t">Tank Levels Over Time</span><span class="cd-t" style="color:var(--t2)">Hourly Β· Litres</span></div><div class="cd-b"><canvas id="wt-tanks" height="200"></canvas></div></div></div>
|
| 213 |
+
<div class="g g2" style="margin-bottom:14px">
|
| 214 |
+
<div class="cd"><div class="cd-h"><span class="cd-t">Daily Usage by Source</span><span class="cd-t" style="color:var(--t2)">Litres</span></div><div class="cd-b"><canvas id="wt-daily" height="220"></canvas></div></div>
|
| 215 |
+
<div class="cd"><div class="cd-h"><span class="cd-t">Avg Hourly Profile</span><span class="cd-t" style="color:var(--t2)">Litres/hour</span></div><div class="cd-b"><canvas id="wt-hourly" height="220"></canvas></div></div>
|
| 216 |
+
</div>
|
| 217 |
+
<div class="g g2">
|
| 218 |
+
<div class="cd"><div class="cd-h"><span class="cd-t">Total Water Split</span></div><div class="cd-b"><div class="donut-w"><canvas id="wt-donut" height="220"></canvas></div></div></div>
|
| 219 |
+
<div class="cd"><div class="cd-h"><span class="cd-t">Pump Activity</span><span class="cd-t" style="color:var(--t2)">15-min Lpm</span></div><div class="cd-b"><canvas id="wt-pump" height="220"></canvas></div></div>
|
| 220 |
+
</div>
|
| 221 |
+
</div>
|
| 222 |
+
</template>
|
| 223 |
+
|
| 224 |
+
<!-- BUDGET -->
|
| 225 |
+
<template v-if="pg==='budget'">
|
| 226 |
+
<div class="ph"><div><h2>Budget Analysis</h2><div class="sub">Planned vs actual resource consumption</div></div></div>
|
| 227 |
+
<div class="pc">
|
| 228 |
+
<div class="g g2" style="margin-bottom:14px">
|
| 229 |
+
<div class="cd"><div class="cd-h"><span class="cd-t">Power: Budget vs Actual</span><span class="cd-t" style="color:var(--t2)">Trip kWh</span></div><div class="cd-b"><canvas id="bg-power" height="260"></canvas></div></div>
|
| 230 |
+
<div class="cd"><div class="cd-h"><span class="cd-t">Water: Budget vs Actual</span><span class="cd-t" style="color:var(--t2)">Trip Litres</span></div><div class="cd-b"><canvas id="bg-water" height="260"></canvas></div></div>
|
| 231 |
+
</div>
|
| 232 |
+
<div class="g g1" style="margin-bottom:14px"><div class="cd"><div class="cd-h"><span class="cd-t">Daily Efficiency Trend</span><span class="cd-t" style="color:var(--t2)">Solar coverage & battery %</span></div><div class="cd-b"><canvas id="bg-trend" height="180"></canvas></div></div></div>
|
| 233 |
+
<div class="g g2">
|
| 234 |
+
<div class="cd"><div class="cd-h"><span class="cd-t">Power Budget Detail</span><span class="cd-t" style="color:var(--t2)">kWh/day</span></div><div class="cd-b"><div v-for="(v,k) in pBudget" :key="k" style="display:flex;align-items:center;gap:10px;padding:5px 0"><span style="width:90px;font:10px var(--mono);color:var(--t2);text-transform:uppercase">{{fmtK(k)}}</span><div style="flex:1;height:14px;background:var(--bg-0);border-radius:3px;overflow:hidden"><div :style="{height:'100%',width:bPct(v,pBMax)+'%',background:bCol(k),borderRadius:'3px'}"></div></div><span style="width:60px;text-align:right;font:11px var(--mono);color:var(--t1)">{{v}}</span></div></div></div>
|
| 235 |
+
<div class="cd"><div class="cd-h"><span class="cd-t">Water Budget Detail</span><span class="cd-t" style="color:var(--t2)">L/day</span></div><div class="cd-b"><div v-for="(v,k) in wBudget" :key="k" style="display:flex;align-items:center;gap:10px;padding:5px 0"><span style="width:90px;font:10px var(--mono);color:var(--t2);text-transform:uppercase">{{fmtK(k)}}</span><div style="flex:1;height:14px;background:var(--bg-0);border-radius:3px;overflow:hidden"><div :style="{height:'100%',width:bPct(v,wBMax)+'%',background:k.includes('shower')?'var(--fresh)':k.includes('toilet')?'var(--black-t)':'var(--accent)',borderRadius:'3px'}"></div></div><span style="width:60px;text-align:right;font:11px var(--mono);color:var(--t1)">{{v}}</span></div></div></div>
|
| 236 |
+
</div>
|
| 237 |
+
</div>
|
| 238 |
+
</template>
|
| 239 |
+
|
| 240 |
+
<!-- COMPONENTS -->
|
| 241 |
+
<template v-if="pg==='components'">
|
| 242 |
+
<div class="ph"><div><h2>Component Catalog</h2><div class="sub">All trailer electrical & water components</div></div></div>
|
| 243 |
+
<div class="pc"><div class="cd"><div class="cd-b" style="padding:0;max-height:calc(100vh - 130px);overflow-y:auto"><table class="tb"><thead><tr><th>Component</th><th>Voltage</th><th>Amps</th><th>Power</th><th>Water</th><th>Idle</th></tr></thead><tbody><template v-for="(items,cat) in comps" :key="cat"><tr><td colspan="6" class="tb-cat">{{cat}}</td></tr><tr v-for="(c,i) in items" :key="i"><td style="color:var(--t1)">{{c.name}}</td><td>{{c.voltage_v}}V</td><td>{{c.avg_amps}}A</td><td style="color:var(--solar)">{{(c.voltage_v*c.avg_amps).toFixed(1)}}W</td><td>{{c.water_gal_per_cycle||'β'}}</td><td>{{c.idle_amps||'β'}}</td></tr></template></tbody></table></div></div></div>
|
| 244 |
+
</template>
|
| 245 |
+
|
| 246 |
+
<!-- GENERATE -->
|
| 247 |
+
<template v-if="pg==='generate'">
|
| 248 |
+
<div class="ph"><div><h2>Generate Data</h2><div class="sub">Configure trip parameters and regenerate simulation</div></div></div>
|
| 249 |
+
<div class="pc"><div class="g g2">
|
| 250 |
+
<div class="cd"><div class="cd-h"><span class="cd-t">Trip Configuration</span></div><div class="cd-b">
|
| 251 |
+
<div class="form-row"><div class="form-group"><label class="form-label">User Profile</label><select class="form-select" v-model="gen.user_type"><option>Glamper</option><option>Typical</option><option>Expert</option></select></div><div class="form-group"><label class="form-label">People</label><select class="form-select" v-model.number="gen.num_people"><option :value="1">1</option><option :value="2">2</option><option :value="3">3</option><option :value="4">4</option></select></div></div>
|
| 252 |
+
<div class="form-row"><div class="form-group"><label class="form-label">Trip Duration (days)</label><input class="form-input" type="number" v-model.number="gen.trip_duration_days" min="1" max="30"></div><div class="form-group"><label class="form-label">Random Seed</label><input class="form-input" type="number" v-model.number="gen.seed" min="1"></div></div>
|
| 253 |
+
<div class="form-row"><div class="form-group"><label class="form-label">Temperature</label><select class="form-select" v-model="gen.temperature"><option>Hot</option><option>Temperate</option><option>Cold</option></select></div><div class="form-group"><label class="form-label">Humidity</label><select class="form-select" v-model="gen.humidity"><option>Humid</option><option>Comfortable</option><option>Dry</option></select></div></div>
|
| 254 |
+
<div class="form-group"><label class="form-label">Sunlight</label><select class="form-select" v-model="gen.sunlight"><option>Hi- Sunny</option><option>Mid- Cloudy</option><option>Lo- Shady</option></select></div>
|
| 255 |
+
<button class="btn btn-primary" :disabled="genBusy" @click="doGen" style="width:100%;margin-top:6px">{{genBusy?'Generating...':'Generate & Reload Dashboard'}}</button>
|
| 256 |
+
<div class="gen-status" :class="{ok:genOk,err:!genOk}" v-if="genMsg">{{genMsg}}</div>
|
| 257 |
+
</div></div>
|
| 258 |
+
<div class="cd"><div class="cd-h"><span class="cd-t">Profile Info</span></div><div class="cd-b" style="font:13px/1.7 var(--sans);color:var(--t2)">
|
| 259 |
+
<div style="margin-bottom:16px"><div style="font:600 14px var(--sans);color:var(--t1);margin-bottom:4px">{{gen.user_type==='Glamper'?'ποΈ Glamper':gen.user_type==='Expert'?'π§βπ§ Expert':'π€ Typical'}}</div><template v-if="gen.user_type==='Glamper'">High comfort β 3 meals/day, long showers, party lighting, dishwasher every meal. Highest resource usage.</template><template v-else-if="gen.user_type==='Expert'">Minimal usage β 1 meal/day, short showers, LED-only. Most efficient, longest off-grid.</template><template v-else>Balanced β 2 meals/day, standard showers, typical electronics. Good comfort/efficiency balance.</template></div>
|
| 260 |
+
<div style="margin-bottom:16px"><div style="font:600 14px var(--sans);color:var(--t1);margin-bottom:4px">{{gen.temperature==='Hot'?'π‘οΈ Hot':gen.temperature==='Cold'?'βοΈ Cold':'π€οΈ Temperate'}}</div><template v-if="gen.temperature==='Hot'">HVAC cooling ~6.9 kWh/day. Best solar. AC compressor is dominant load.</template><template v-else-if="gen.temperature==='Cold'">HVAC heating ~15.6 kWh/day. Reduced solar. Significant overnight drain.</template><template v-else>Mild HVAC ~0.7 kWh/day. Good solar. Most efficient climate.</template></div>
|
| 261 |
+
<div><div style="font:600 14px var(--sans);color:var(--t1);margin-bottom:4px">{{gen.sunlight==='Hi- Sunny'?'βοΈ Full Sun':gen.sunlight==='Lo- Shady'?'π² Shady':'βοΈ Cloudy'}}</div><template v-if="gen.sunlight==='Hi- Sunny'">100% efficiency. Max generation from 35-panel 5.25kW array.</template><template v-else-if="gen.sunlight==='Lo- Shady'">25% efficiency. Will likely need shore power.</template><template v-else>50% efficiency. May be self-sufficient with conservative use.</template></div>
|
| 262 |
+
</div></div>
|
| 263 |
+
</div></div>
|
| 264 |
+
</template>
|
| 265 |
+
|
| 266 |
+
<div v-if="loading" class="ld"><span class="pulse">LOADING DATA...</span></div>
|
| 267 |
+
</main>
|
| 268 |
+
</div>
|
| 269 |
+
|
| 270 |
+
<script>
|
| 271 |
+
const{createApp,ref,reactive,computed,onMounted,watch,nextTick}=Vue;
|
| 272 |
+
const CC={HVAC:'#ff5050',Lighting:'#ffb020',Devices:'#a78bfa',Fridge:'#18d4e8',WaterPump:'#4890ff',Cooking:'#ff8830',Inverter:'#e879f9',Unmetered:'#506070'};
|
| 273 |
+
const CL=['HVAC','Lighting','Devices','Fridge','WaterPump','Cooking','Inverter','Unmetered'];
|
| 274 |
+
Chart.defaults.font.family="'JetBrains Mono','monospace'";Chart.defaults.color='#506070';Chart.defaults.borderColor='#1c2838';
|
| 275 |
+
|
| 276 |
+
// ββ Stable chart registry keyed by canvas ID ββ
|
| 277 |
+
const _charts={};
|
| 278 |
+
function mk(id,type,data,opts){
|
| 279 |
+
const el=document.getElementById(id);if(!el)return null;
|
| 280 |
+
if(_charts[id]){_charts[id].destroy();delete _charts[id];
|
| 281 |
+
const parent=el.parentElement;
|
| 282 |
+
if(parent){
|
| 283 |
+
const fixedH=parseInt(el.getAttribute('data-height'),10);
|
| 284 |
+
el.width=parent.clientWidth;
|
| 285 |
+
el.height=Number.isFinite(fixedH)?fixedH:200;
|
| 286 |
+
}
|
| 287 |
+
}
|
| 288 |
+
const c=new Chart(el,{type,data,options:opts});_charts[id]=c;return c;
|
| 289 |
+
}
|
| 290 |
+
|
| 291 |
+
const B={responsive:true,maintainAspectRatio:false,animation:{duration:350},
|
| 292 |
+
plugins:{legend:{position:'bottom',labels:{color:'#8a9bb0',font:{size:10},boxWidth:10,padding:10}},tooltip:{backgroundColor:'#182230ee',borderColor:'#283848',borderWidth:1,titleFont:{size:11},bodyFont:{size:11},padding:10,cornerRadius:6}},
|
| 293 |
+
scales:{x:{ticks:{color:'#506070',font:{size:9},maxRotation:0},grid:{color:'#1c283880'}},y:{ticks:{color:'#506070',font:{size:9}},grid:{color:'#1c283880'}}}
|
| 294 |
+
};
|
| 295 |
+
function mO(ov){const o=JSON.parse(JSON.stringify(B));(function m(t,s){for(const k in s)if(s[k]&&typeof s[k]==='object'&&!Array.isArray(s[k])){t[k]=t[k]||{};m(t[k],s[k]);}else t[k]=s[k];})(o,ov);return o;}
|
| 296 |
+
function fT(ts){if(!ts)return'';const d=new Date(ts);return d.toLocaleString('en-US',{month:'short',day:'numeric',hour:'2-digit',minute:'2-digit',hour12:false});}
|
| 297 |
+
function fH(h){return`${String(h).padStart(2,'0')}:00`}
|
| 298 |
+
|
| 299 |
+
createApp({
|
| 300 |
+
setup(){
|
| 301 |
+
const pg=ref('overview'),loading=ref(true);
|
| 302 |
+
const cfg=ref({}),S=ref({trip_days:0,total_solar_kwh:0,total_consumption_kwh:0,self_sufficiency_pct:0,circuit_totals_kwh:{},battery:{},water:{},daily_breakdown:[]});
|
| 303 |
+
const pBudget=ref({}),wBudget=ref({}),comps=ref({}),hProfile=ref([]),whProfile=ref([]);
|
| 304 |
+
const pDay=ref(0),pDayInsight=ref('');
|
| 305 |
+
const gen=reactive({user_type:'Typical',num_people:2,trip_duration_days:5,temperature:'Hot',sunlight:'Hi- Sunny',humidity:'Comfortable',seed:42});
|
| 306 |
+
const genBusy=ref(false),genMsg=ref(''),genOk=ref(true);
|
| 307 |
+
let pw15=[],pwH=[],wtH=[],wtD=[],wt15=[];
|
| 308 |
+
|
| 309 |
+
const pBMax=computed(()=>Math.max(...Object.values(pBudget.value||{}),1));
|
| 310 |
+
const wBMax=computed(()=>Math.max(...Object.values(wBudget.value||{}),1));
|
| 311 |
+
const battCol=computed(()=>{const p=S.value.battery?.current_pct||0;return p>60?'#2ee8a8':p>30?'#ffb020':'#ff4040';});
|
| 312 |
+
|
| 313 |
+
function rd(v){return Math.round((v||0)*100)/100}
|
| 314 |
+
function fL(v){return v!=null?Math.round(v):'β'}
|
| 315 |
+
function fmtK(k){return k.replace(/_/g,' ').replace(/kwh|L/gi,'').trim()}
|
| 316 |
+
function bPct(v,mx){return Math.min(100,(v||0)/mx*100)}
|
| 317 |
+
function bCol(k){if(k.includes('solar'))return'var(--solar)';if(k.includes('hvac'))return'var(--hvac)';if(k.includes('cook'))return'var(--cook)';if(k.includes('light'))return'var(--solar)';if(k.includes('device'))return'#a78bfa';if(k.includes('fridge'))return'var(--fresh)';if(k.includes('pump'))return'var(--batt)';return'var(--accent)';}
|
| 318 |
+
async function api(u){return(await fetch(u)).json();}
|
| 319 |
+
|
| 320 |
+
async function loadAll(){
|
| 321 |
+
loading.value=true;
|
| 322 |
+
try{
|
| 323 |
+
const[c,s,pb,wb,co,hp,whp]=await Promise.all([api('/api/config'),api('/api/summary'),api('/api/power/budget'),api('/api/water/budget'),api('/api/components'),api('/api/power/hourly-profile'),api('/api/water/hourly-profile')]);
|
| 324 |
+
cfg.value=c;S.value=s;pBudget.value=pb;wBudget.value=wb;comps.value=co;hProfile.value=hp;whProfile.value=whp;
|
| 325 |
+
const p=c.inputs?.params||{};gen.user_type=p.user_type?.value||'Typical';gen.num_people=p.num_people?.value||2;gen.trip_duration_days=p.trip_duration_days?.value||5;gen.temperature=p.temperature?.value||'Hot';gen.sunlight=p.sunlight?.value||'Hi- Sunny';gen.humidity=p.humidity?.value||'Comfortable';
|
| 326 |
+
}catch(e){console.error(e);}
|
| 327 |
+
loading.value=false;
|
| 328 |
+
}
|
| 329 |
+
|
| 330 |
+
// ββ Overview ββ
|
| 331 |
+
function renderOV(){
|
| 332 |
+
const s=S.value;if(!s.daily_breakdown?.length)return;const db=s.daily_breakdown;
|
| 333 |
+
mk('ov-energy','bar',{labels:db.map(d=>`Day ${d.day}`),datasets:[
|
| 334 |
+
{label:'Solar',data:db.map(d=>d.solar_kwh),backgroundColor:'#ffb020cc',borderRadius:5,barPercentage:.55},
|
| 335 |
+
{label:'Load',data:db.map(d=>-d.consumption_kwh),backgroundColor:'#ff5050cc',borderRadius:5,barPercentage:.55},
|
| 336 |
+
{label:'Shore',data:db.map(d=>d.shore_kwh),backgroundColor:'#b48afacc',borderRadius:5,barPercentage:.55},
|
| 337 |
+
]},mO({plugins:{legend:{display:true},tooltip:{callbacks:{label:c=>`${c.dataset.label}: ${Math.abs(c.raw).toFixed(2)} kWh`}},annotation:{annotations:{zero:{type:'line',yMin:0,yMax:0,borderColor:'#28384888',borderWidth:1,borderDash:[4,4]}}}},scales:{y:{title:{display:true,text:'kWh',color:'#506070',font:{size:10}}}}}));
|
| 338 |
+
|
| 339 |
+
const ct=s.circuit_totals_kwh||{};const ll=Object.keys(ct).filter(k=>ct[k]>0);const vv=ll.map(l=>Math.round(ct[l]*100)/100);const tot=vv.reduce((a,b)=>a+b,0);
|
| 340 |
+
mk('ov-donut','doughnut',{labels:ll,datasets:[{data:vv,backgroundColor:ll.map(l=>CC[l]||'#506070'),borderWidth:0,hoverOffset:6}]},
|
| 341 |
+
{responsive:true,maintainAspectRatio:true,cutout:'62%',plugins:{legend:{position:'right',labels:{color:'#8a9bb0',font:{size:10},boxWidth:10,padding:8}},tooltip:{callbacks:{label:c=>`${c.label}: ${c.raw} kWh (${Math.round(c.raw/tot*100)}%)`}}}});
|
| 342 |
+
}
|
| 343 |
+
|
| 344 |
+
// ββ Power ββ
|
| 345 |
+
async function loadPW(){
|
| 346 |
+
const dq=pDay.value>0?`&day=${pDay.value}`:'';
|
| 347 |
+
const[r1,r2]=await Promise.all([api(`/api/power/15MIN?limit=10000${dq}`),api(`/api/power/1H?limit=5000${dq}`)]);
|
| 348 |
+
pw15=r1.data||[];pwH=r2.data||[];
|
| 349 |
+
if(pDay.value>0){const db=(S.value.daily_breakdown||[]).find(d=>d.day===pDay.value);
|
| 350 |
+
if(db){const n=rd(db.solar_kwh-db.consumption_kwh);pDayInsight.value=`Day ${db.day}: <b>${db.solar_kwh} kWh</b> solar, <b>${db.consumption_kwh} kWh</b> consumed. Net: <b style="color:${n>=0?'var(--accent)':'var(--danger)'}">${n>0?'+':''}${n} kWh</b>. Battery ended at <b>${db.battery_end_pct}%</b>.`;}
|
| 351 |
+
}else pDayInsight.value='';
|
| 352 |
+
await nextTick();renderPW();
|
| 353 |
+
}
|
| 354 |
+
function renderPW(){
|
| 355 |
+
if(!pw15.length)return;const lb=pw15.map(r=>fT(r.Time));const tl=pDay.value?12:20;
|
| 356 |
+
|
| 357 |
+
mk('pw-solar','line',{labels:lb,datasets:[
|
| 358 |
+
{label:'Solar',data:pw15.map(r=>r.Solar_Flow_kW||0),borderColor:'#ffb020',backgroundColor:'rgba(255,176,32,.06)',fill:true,pointRadius:0,borderWidth:1.5,tension:.35},
|
| 359 |
+
{label:'Total Load',data:pw15.map(r=>CL.reduce((s,c)=>s+(r[`${c}_Flow_kW`]||0),0)),borderColor:'#ff5050',backgroundColor:'rgba(255,80,80,.04)',fill:true,pointRadius:0,borderWidth:1.5,tension:.35},
|
| 360 |
+
]},mO({interaction:{intersect:false,mode:'index'},scales:{x:{ticks:{maxTicksLimit:tl}},y:{title:{display:true,text:'kW',color:'#506070',font:{size:10}}}},plugins:{tooltip:{callbacks:{label:c=>`${c.dataset.label}: ${c.raw.toFixed(3)} kW`}}}}));
|
| 361 |
+
|
| 362 |
+
mk('pw-batt','line',{labels:lb,datasets:[{label:'Battery %',data:pw15.map(r=>r.Battery_Level_Pct||0),borderColor:'#4890ff',backgroundColor:'rgba(72,144,255,.08)',fill:true,pointRadius:0,borderWidth:1.5,tension:.3}]},
|
| 363 |
+
mO({scales:{x:{ticks:{maxTicksLimit:tl}},y:{min:0,max:100,title:{display:true,text:'%',color:'#506070'}}},plugins:{annotation:{annotations:{
|
| 364 |
+
dzone:{type:'box',yMin:0,yMax:20,backgroundColor:'rgba(255,64,64,.05)',borderWidth:0},
|
| 365 |
+
wzone:{type:'box',yMin:20,yMax:40,backgroundColor:'rgba(255,160,32,.03)',borderWidth:0},
|
| 366 |
+
crit:{type:'line',yMin:20,yMax:20,borderColor:'#ff404055',borderWidth:1,borderDash:[4,4],label:{display:true,content:'Critical 20%',position:'end',color:'#ff4040',font:{size:8},backgroundColor:'transparent'}},
|
| 367 |
+
}}}}));
|
| 368 |
+
|
| 369 |
+
if(hProfile.value?.length){const hp=hProfile.value;
|
| 370 |
+
mk('pw-hourly','bar',{labels:hp.map(h=>fH(h.hour)),datasets:CL.filter(c=>c!=='Unmetered').map(c=>({label:c,data:hp.map(h=>h[`${c}_kwh`]||0),backgroundColor:CC[c]+'cc',borderRadius:2,barPercentage:.9,categoryPercentage:.85}))},mO({scales:{x:{stacked:true,ticks:{maxTicksLimit:12}},y:{stacked:true,title:{display:true,text:'kWh',color:'#506070'}}}}));}
|
| 371 |
+
|
| 372 |
+
if(pwH.length){
|
| 373 |
+
mk('pw-stack','bar',{labels:pwH.map(r=>fT(r.Time)),datasets:CL.filter(c=>c!=='Unmetered').map(c=>({label:c,data:pwH.map(r=>r[`${c}_Total_kWh`]||0),backgroundColor:CC[c]+'aa',borderRadius:1,barPercentage:.95}))},mO({scales:{x:{stacked:true,ticks:{maxTicksLimit:tl}},y:{stacked:true,title:{display:true,text:'kWh',color:'#506070'}}}}));
|
| 374 |
+
|
| 375 |
+
mk('pw-source','line',{labels:pwH.map(r=>fT(r.Time)),datasets:[
|
| 376 |
+
{label:'Solar',data:pwH.map(r=>r.Solar_Total_kWh||0),borderColor:'#ffb020',backgroundColor:'rgba(255,176,32,.12)',fill:true,pointRadius:0,borderWidth:1.5,tension:.3},
|
| 377 |
+
{label:'Battery Out',data:pwH.map(r=>r.Battery_Discharged_kWh||0),borderColor:'#4890ff',backgroundColor:'rgba(72,144,255,.1)',fill:true,pointRadius:0,borderWidth:1.5,tension:.3},
|
| 378 |
+
{label:'Shore',data:pwH.map(r=>r.Shore_Total_kWh||0),borderColor:'#b48afa',backgroundColor:'rgba(180,138,250,.1)',fill:true,pointRadius:0,borderWidth:1.5,tension:.3},
|
| 379 |
+
]},mO({interaction:{intersect:false,mode:'index'},scales:{x:{ticks:{maxTicksLimit:tl}},y:{stacked:true,title:{display:true,text:'kWh',color:'#506070'}}}}));
|
| 380 |
+
}
|
| 381 |
+
}
|
| 382 |
+
function setPDay(d){pDay.value=d;loadPW();}
|
| 383 |
+
|
| 384 |
+
// ββ Water ββ
|
| 385 |
+
async function loadWT(){
|
| 386 |
+
const[a,b,c]=await Promise.all([api('/api/water/1H?limit=5000'),api('/api/water/1DAY?limit=30'),api('/api/water/15MIN?limit=5000')]);
|
| 387 |
+
wtH=a.data||[];wtD=b.data||[];wt15=c.data||[];await nextTick();renderWT();
|
| 388 |
+
}
|
| 389 |
+
function renderWT(){
|
| 390 |
+
if(!wtH.length)return;
|
| 391 |
+
const fc=cfg.value?.trailer_specs?.specs?.freshwater_capacity_gal?.value*3.785||378;
|
| 392 |
+
const gc=cfg.value?.trailer_specs?.specs?.greywater_capacity_gal?.value*3.785||189;
|
| 393 |
+
|
| 394 |
+
mk('wt-tanks','line',{labels:wtH.map(r=>fT(r.Time)),datasets:[
|
| 395 |
+
{label:'Fresh',data:wtH.map(r=>r.FreshTank_Level_L||0),borderColor:'#18d4e8',backgroundColor:'rgba(24,212,232,.06)',fill:true,pointRadius:0,borderWidth:1.5,tension:.3},
|
| 396 |
+
{label:'Grey',data:wtH.map(r=>r.GreyTank_Level_L||0),borderColor:'#7888a0',backgroundColor:'rgba(120,136,160,.04)',fill:true,pointRadius:0,borderWidth:1.5,tension:.3},
|
| 397 |
+
{label:'Black',data:wtH.map(r=>r.BlackTank_Level_L||0),borderColor:'#585858',backgroundColor:'rgba(88,88,88,.04)',fill:true,pointRadius:0,borderWidth:1.5,tension:.3},
|
| 398 |
+
]},mO({interaction:{intersect:false,mode:'index'},scales:{x:{ticks:{maxTicksLimit:14}},y:{title:{display:true,text:'Litres',color:'#506070'}}},plugins:{tooltip:{callbacks:{label:c=>`${c.dataset.label}: ${c.raw.toFixed(1)} L`}},annotation:{annotations:{fcap:{type:'line',yMin:fc,yMax:fc,borderColor:'#18d4e833',borderWidth:1,borderDash:[3,3],label:{display:true,content:`Fresh cap (${Math.round(fc)}L)`,position:'start',color:'#18d4e8',font:{size:8},backgroundColor:'transparent'}},gcap:{type:'line',yMin:gc,yMax:gc,borderColor:'#7888a033',borderWidth:1,borderDash:[3,3]}}}}}));
|
| 399 |
+
|
| 400 |
+
if(wtD.length){mk('wt-daily','bar',{labels:wtD.map((_,i)=>`Day ${i+1}`),datasets:[
|
| 401 |
+
{label:'Shower',data:wtD.map(r=>Math.round(r.Shower_Total_L||0)),backgroundColor:'#18d4e8cc',borderRadius:4},
|
| 402 |
+
{label:'Kitchen',data:wtD.map(r=>Math.round(r.Kitchen_Total_L||0)),backgroundColor:'#2ee8a8cc',borderRadius:4},
|
| 403 |
+
{label:'Toilet',data:wtD.map(r=>Math.round(r.Toilet_Total_L||0)),backgroundColor:'#585858cc',borderRadius:4},
|
| 404 |
+
]},mO({scales:{x:{stacked:true},y:{stacked:true,title:{display:true,text:'Litres',color:'#506070'}}}}));}
|
| 405 |
+
|
| 406 |
+
if(whProfile.value?.length){const wp=whProfile.value;mk('wt-hourly','bar',{labels:wp.map(h=>fH(h.hour)),datasets:[
|
| 407 |
+
{label:'Shower',data:wp.map(h=>h.Shower_L||0),backgroundColor:'#18d4e8cc',borderRadius:2},
|
| 408 |
+
{label:'Kitchen',data:wp.map(h=>h.Kitchen_L||0),backgroundColor:'#2ee8a8cc',borderRadius:2},
|
| 409 |
+
{label:'Toilet',data:wp.map(h=>h.Toilet_L||0),backgroundColor:'#585858cc',borderRadius:2},
|
| 410 |
+
]},mO({scales:{x:{stacked:true,ticks:{maxTicksLimit:12}},y:{stacked:true,title:{display:true,text:'Litres',color:'#506070'}}}}));}
|
| 411 |
+
|
| 412 |
+
if(wtD.length){const t={S:0,K:0,T:0};wtD.forEach(r=>{t.S+=r.Shower_Total_L||0;t.K+=r.Kitchen_Total_L||0;t.T+=r.Toilet_Total_L||0;});const tt=t.S+t.K+t.T;
|
| 413 |
+
mk('wt-donut','doughnut',{labels:['Shower','Kitchen','Toilet'],datasets:[{data:[Math.round(t.S),Math.round(t.K),Math.round(t.T)],backgroundColor:['#18d4e8','#2ee8a8','#585858'],borderWidth:0,hoverOffset:6}]},
|
| 414 |
+
{responsive:true,maintainAspectRatio:true,cutout:'62%',plugins:{legend:{position:'right',labels:{color:'#8a9bb0',font:{size:10},boxWidth:10,padding:8}},tooltip:{callbacks:{label:c=>`${c.label}: ${c.raw} L (${Math.round(c.raw/tt*100)}%)`}}}});}
|
| 415 |
+
|
| 416 |
+
if(wt15.length){const pm=wt15.map(r=>r.Pump_Flow_Lpm||0);
|
| 417 |
+
mk('wt-pump','bar',{labels:wt15.map(r=>fT(r.Time)),datasets:[{label:'Pump',data:pm,backgroundColor:pm.map(v=>`rgba(24,212,232,${Math.min(.9,v/.4+.08)})`),borderRadius:1,barPercentage:1,categoryPercentage:1}]},mO({plugins:{legend:{display:false}},scales:{x:{ticks:{maxTicksLimit:14}},y:{title:{display:true,text:'Lpm',color:'#506070'}}}}));}
|
| 418 |
+
}
|
| 419 |
+
|
| 420 |
+
// ββ Budget ββ
|
| 421 |
+
async function loadBG(){if(!wtD.length){const r=await api('/api/water/1DAY?limit=30');wtD=r.data||[];}await nextTick();renderBG();}
|
| 422 |
+
function renderBG(){
|
| 423 |
+
const s=S.value;if(!s.trip_days)return;const pb=pBudget.value,wb=wBudget.value,days=s.trip_days,ct=s.circuit_totals_kwh||{};
|
| 424 |
+
const cM={hvac_kwh:'HVAC',lighting_kwh:'Lighting',devices_kwh:'Devices',fridge_kwh:'Fridge',water_pump_kwh:'WaterPump',cooking_kwh:'Cooking',inverter_kwh:'Inverter'};
|
| 425 |
+
const bL=Object.keys(cM).map(k=>cM[k]),bB=Object.keys(cM).map(k=>rd((pb[k]||0)*days)),bA=Object.keys(cM).map(k=>rd(ct[cM[k]]||0));
|
| 426 |
+
|
| 427 |
+
mk('bg-power','bar',{labels:bL,datasets:[
|
| 428 |
+
{label:'Budget',data:bB,backgroundColor:'rgba(46,232,168,.3)',borderColor:'#2ee8a8',borderWidth:1,borderRadius:5,barPercentage:.55},
|
| 429 |
+
{label:'Actual',data:bA,backgroundColor:'rgba(255,80,80,.3)',borderColor:'#ff5050',borderWidth:1,borderRadius:5,barPercentage:.55},
|
| 430 |
+
]},mO({scales:{y:{title:{display:true,text:'kWh (trip)',color:'#506070'}}},plugins:{tooltip:{callbacks:{label:c=>`${c.dataset.label}: ${c.raw} kWh`}}}}));
|
| 431 |
+
|
| 432 |
+
const wL=['Shower','Kitchen','Toilet'],wB=[rd(wb.shower_L*days),rd(wb.kitchen_L*days),rd(wb.toilet_L*days)];let wA=[0,0,0];wtD.forEach(r=>{wA[0]+=r.Shower_Total_L||0;wA[1]+=r.Kitchen_Total_L||0;wA[2]+=r.Toilet_Total_L||0;});wA=wA.map(v=>Math.round(v));
|
| 433 |
+
mk('bg-water','bar',{labels:wL,datasets:[
|
| 434 |
+
{label:'Budget',data:wB,backgroundColor:'rgba(24,212,232,.3)',borderColor:'#18d4e8',borderWidth:1,borderRadius:5,barPercentage:.55},
|
| 435 |
+
{label:'Actual',data:wA,backgroundColor:'rgba(88,88,88,.35)',borderColor:'#585858',borderWidth:1,borderRadius:5,barPercentage:.55},
|
| 436 |
+
]},mO({scales:{y:{title:{display:true,text:'Litres (trip)',color:'#506070'}}}}));
|
| 437 |
+
|
| 438 |
+
const db=s.daily_breakdown||[];
|
| 439 |
+
mk('bg-trend','line',{labels:db.map(d=>`Day ${d.day}`),datasets:[
|
| 440 |
+
{label:'Solar Coverage %',data:db.map(d=>Math.min(200,Math.round(d.solar_kwh/Math.max(d.consumption_kwh,.01)*100))),borderColor:'#2ee8a8',backgroundColor:'rgba(46,232,168,.06)',fill:true,pointRadius:5,pointBackgroundColor:'#2ee8a8',borderWidth:2,tension:.3},
|
| 441 |
+
{label:'Battery End %',data:db.map(d=>d.battery_end_pct),borderColor:'#4890ff',backgroundColor:'rgba(72,144,255,.04)',fill:false,pointRadius:5,pointBackgroundColor:'#4890ff',borderWidth:2,tension:.3},
|
| 442 |
+
]},mO({scales:{y:{min:0,title:{display:true,text:'%',color:'#506070'}}},plugins:{annotation:{annotations:{target:{type:'line',yMin:100,yMax:100,borderColor:'#2ee8a855',borderWidth:1,borderDash:[4,4],label:{display:true,content:'100% self-sufficient',position:'end',color:'#2ee8a8',font:{size:8},backgroundColor:'transparent'}}}}}}));
|
| 443 |
+
}
|
| 444 |
+
|
| 445 |
+
// ββ Generate ββ
|
| 446 |
+
async function doGen(){
|
| 447 |
+
genBusy.value=true;genMsg.value='Generating simulation data...';genOk.value=true;
|
| 448 |
+
try{
|
| 449 |
+
const r=await fetch('/api/generate',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(gen)});
|
| 450 |
+
const d=await r.json();
|
| 451 |
+
if(r.ok){genMsg.value='β '+d.message+'. Reloading...';genOk.value=true;pw15=[];pwH=[];wtH=[];wtD=[];wt15=[];await loadAll();genMsg.value='β Dashboard refreshed!';}
|
| 452 |
+
else{genMsg.value='β '+(d.error||'Error');genOk.value=false;}
|
| 453 |
+
}catch(e){genMsg.value='β '+e.message;genOk.value=false;}
|
| 454 |
+
genBusy.value=false;
|
| 455 |
+
}
|
| 456 |
+
|
| 457 |
+
function go(p){pg.value=p;}
|
| 458 |
+
watch(pg,async p=>{await nextTick();if(p==='overview')renderOV();if(p==='power')loadPW();if(p==='water')loadWT();if(p==='budget')loadBG();});
|
| 459 |
+
onMounted(async()=>{await loadAll();await nextTick();renderOV();});
|
| 460 |
+
|
| 461 |
+
return{pg,loading,cfg,S,pBudget,wBudget,comps,hProfile,whProfile,pDay,pDayInsight,gen,genBusy,genMsg,genOk,battCol,pBMax,wBMax,rd,fL,fmtK,bPct,bCol,go,setPDay,doGen};
|
| 462 |
+
}
|
| 463 |
+
}).mount('#app');
|
| 464 |
+
</script>
|
| 465 |
+
</body>
|
| 466 |
+
</html>
|