-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathBatteryROI_split.html
More file actions
6294 lines (5839 loc) · 494 KB
/
BatteryROI_split.html
File metadata and controls
6294 lines (5839 loc) · 494 KB
1
2
3
4
5
6
7
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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>⚡ Battery ROI Calculator</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/7.23.9/babel.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prop-types/15.8.1/prop-types.min.js"></script>
<script src="https://unpkg.com/recharts@2.12.7/umd/Recharts.js"></script>
<style>
:root {
--bg-page: #0a0f1a;
--bg-page-end: #111827;
--bg-page-mid: #0d1321;
--bg-card: rgba(22,33,52,0.8);
--bg-input: #0f172a;
--bg-header: #0c1222;
--bg-hover: #1e293b;
--bg-row-alt: rgba(10,15,26,0.3);
--border: #1e293b;
--border-accent: #1e3a5f;
--border-light: #334155;
--text: #e2e8f0;
--text-secondary: #94a3b8;
--text-muted: #64748b;
--text-dim: #475569;
--scrollbar-track: #0a0f1a;
--scrollbar-thumb: #334155;
--select-bg: #0f172a;
--range-bg: #1e293b;
}
[data-theme="light"] {
--bg-page: #f1f5f9;
--bg-page-end: #e2e8f0;
--bg-page-mid: #f8fafc;
--bg-card: #ffffff;
--bg-input: #ffffff;
--bg-header: #f1f5f9;
--bg-hover: #e2e8f0;
--bg-row-alt: rgba(0,0,0,0.04);
--border: #cbd5e1;
--border-accent: #93c5fd;
--border-light: #94a3b8;
--text: #1e293b;
--text-secondary: #475569;
--text-muted: #64748b;
--text-dim: #94a3b8;
--scrollbar-track: #f1f5f9;
--scrollbar-thumb: #94a3b8;
--select-bg: #ffffff;
--range-bg: #cbd5e1;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body { background: var(--bg-page); }
#root { min-height: 100vh; }
input[type="range"] { -webkit-appearance: none; height: 6px; background: var(--range-bg); border-radius: 3px; outline: none; }
input[type="range"]::-webkit-slider-thumb { -webkit-appearance: none; width: 16px; height: 16px; border-radius: 50%; background: #f59e0b; cursor: pointer; }
input[type="range"]::-moz-range-thumb { width: 16px; height: 16px; border-radius: 50%; background: #f59e0b; cursor: pointer; border: none; }
input[type="number"]::-webkit-inner-spin-button, input[type="number"]::-webkit-outer-spin-button { opacity: 0.5; }
select option { background: var(--select-bg); color: var(--text); }
::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-track { background: var(--scrollbar-track); }
::-webkit-scrollbar-thumb { background: var(--scrollbar-thumb); border-radius: 3px; }
@keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.3; } }
</style>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
/* ══════════════════════════════════════════════════════════════
Battery ROI Calculator — Shared Config & Constants
══════════════════════════════════════════════════════════════ */
/* ── Weather Forecast Configuration ── */
const WEATHER_API_KEY = '4c5098037db74b3f980113023260602'; // WeatherAPI.com key
const WEATHER_API_URL = 'https://api.weatherapi.com/v1/forecast.json';
const ADELAIDE_LOCATION = '-34.8481,138.5597'; // Ferryden Park, SA (precise coordinates)
// Weather to solar generation correlation (based on historical data analysis)
const WEATHER_SOLAR_CORRELATION = {
// cloud_cover % -> solar generation multiplier
getSolarMultiplier: (cloudCover, uvIndex) => {
// Base on cloud cover
let multiplier = 1.0;
if (cloudCover <= 10) multiplier = 1.0; // Clear
else if (cloudCover <= 30) multiplier = 0.9; // Mostly clear
else if (cloudCover <= 50) multiplier = 0.7; // Partly cloudy
else if (cloudCover <= 70) multiplier = 0.5; // Mostly cloudy
else if (cloudCover <= 90) multiplier = 0.3; // Overcast
else multiplier = 0.15; // Heavy cloud/rain
// Adjust by UV index (0-11+ scale)
const uvMultiplier = Math.min(uvIndex / 8, 1.0);
return multiplier * (0.7 + 0.3 * uvMultiplier);
}
};
/* ═══════════════════════════════════════════════════════════════════════
HOME ASSISTANT BOM WEATHER INTEGRATION
Fetches BOM weather data from Home Assistant's weather-au integration
═══════════════════════════════════════════════════════════════════════ */
// Solar API Configuration (Nexus server with Solax collector)
// Use relative path when served from any web server (local or Cloudflare tunnel), absolute only for file://
const SOLAR_API_URL = (window.location.protocol === 'file:') ? 'http://192.168.68.60:5000/api/solar' : '/api/solar';
const SOLAR_POLL_INTERVAL = 30000; // 30 seconds
// Local date helper — toISOString() uses UTC which gives yesterday in ACDT before 10:30am
function localDateStr(d) {
var dt = d || new Date();
return dt.getFullYear() + '-' + String(dt.getMonth() + 1).padStart(2, '0') + '-' + String(dt.getDate()).padStart(2, '0');
}
// Home Assistant Configuration
const HA_CONFIG = {
url: 'http://192.168.68.60:8123',
weatherEntity: 'weather.forecast_home', // Your BOM weather entity
// Long-Lived Access Token (hardcoded for convenience)
token: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJlNzdjOWRmODQwNjQ0NmIxOGMxMmNkYjAwOGQ5OTA3MSIsImlhdCI6MTc3MDM4MTU2NywiZXhwIjoyMDg1NzQxNTY3fQ.j_MRtPHcysiCzbPv3ZD2DZW-p20ZAeZEyJzlUSexCLg'
};
// Weather condition to solar multiplier mapping (from BOM data)
const BOM_CONDITION_TO_SOLAR = {
// Clear conditions (90-100% solar)
'clear': 1.0,
'sunny': 1.0,
'clear-night': 1.0,
// Mostly clear (80-90% solar)
'partlycloudy': 0.85,
'partly-cloudy': 0.85,
// Partly cloudy (65-75% solar)
'cloudy': 0.7,
'mostlycloudy': 0.65,
'mostly-cloudy': 0.65,
// Overcast (40-55% solar)
'overcast': 0.5,
// Light rain/showers (25-35% solar)
'rainy': 0.3,
'light-rain': 0.35,
'shower': 0.3,
'showers': 0.3,
// Heavy rain/storms (10-20% solar)
'pouring': 0.15,
'heavy-rain': 0.15,
'lightning': 0.1,
'lightning-rainy': 0.1,
'thunderstorm': 0.1,
// Other conditions
'fog': 0.4,
'hail': 0.2,
'snowy': 0.2,
'snowy-rainy': 0.2,
'windy': 0.85,
'windy-variant': 0.8,
'exceptional': 0.5,
};
async function fetchHAWeatherForecast() {
// Check if token is set
if (!HA_CONFIG.token) {
const token = prompt(
'Enter your Home Assistant Long-Lived Access Token:\n\n' +
'(You only need to do this once per session)\n\n' +
'Get it from: Settings → People → [Your Name] → Security → Long-Lived Access Tokens'
);
if (!token) {
throw new Error('Home Assistant access token required');
}
HA_CONFIG.token = token;
}
const authHeaders = {
'Authorization': `Bearer ${HA_CONFIG.token}`,
'Content-Type': 'application/json'
};
try {
// Step 1: Get current weather state (temp, humidity, condition)
const stateResponse = await fetch(
`${HA_CONFIG.url}/api/states/${HA_CONFIG.weatherEntity}`,
{ method: 'GET', headers: authHeaders }
);
if (!stateResponse.ok) {
if (stateResponse.status === 401) {
HA_CONFIG.token = null;
throw new Error('Invalid Home Assistant token. Please check your token and try again.');
}
throw new Error(`Home Assistant API error: ${stateResponse.status}`);
}
const stateData = await stateResponse.json();
// Step 2: Get forecast via weather.get_forecasts service call
// (HA 2024.3+ moved forecasts out of entity attributes into a service)
const forecastResponse = await fetch(
`${HA_CONFIG.url}/api/services/weather/get_forecasts?return_response`,
{
method: 'POST',
headers: authHeaders,
body: JSON.stringify({
entity_id: HA_CONFIG.weatherEntity,
type: 'daily'
})
}
);
if (!forecastResponse.ok) {
throw new Error(`Home Assistant forecast service error: ${forecastResponse.status}`);
}
const forecastData = await forecastResponse.json();
// Extract forecast array from service response
const forecast = forecastData?.service_response?.[HA_CONFIG.weatherEntity]?.forecast || [];
if (forecast.length === 0) {
throw new Error('No forecast data available from Home Assistant');
}
return {
location: stateData.attributes?.friendly_name || 'Unknown',
current: {
temp: stateData.attributes?.temperature,
condition: stateData.state,
humidity: stateData.attributes?.humidity,
pressure: stateData.attributes?.pressure
},
forecast: forecast.map(day => ({
datetime: day.datetime,
date: day.datetime.split('T')[0],
condition: day.condition,
temperature: day.temperature,
templow: day.templow,
precipitation: day.precipitation,
precipitation_probability: day.precipitation_probability,
wind_speed: day.wind_speed,
// Calculate solar multiplier based on condition
solar_multiplier: BOM_CONDITION_TO_SOLAR[day.condition] || 0.5
}))
};
} catch (error) {
console.error('Home Assistant fetch error:', error);
throw error;
}
}
// Get icon for condition
function getConditionIcon(condition) {
const iconMap = {
'clear': '\u2600\uFE0F',
'sunny': '\u2600\uFE0F',
'partlycloudy': '\u26C5',
'partly-cloudy': '\u26C5',
'cloudy': '\u2601\uFE0F',
'overcast': '\u2601\uFE0F',
'rainy': '\uD83C\uDF27\uFE0F',
'pouring': '\uD83C\uDF27\uFE0F',
'lightning': '\u26C8\uFE0F',
'thunderstorm': '\u26C8\uFE0F',
'fog': '\uD83C\uDF2B\uFE0F',
'windy': '\uD83D\uDCA8',
'snowy': '\uD83C\uDF28\uFE0F',
};
return iconMap[condition] || '\uD83C\uDF24\uFE0F';
}
// loadForecastFromHA removed — now uses server-side proxy via /api/solar/weather
const { BarChart, Bar, AreaChart, Area, LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend, ResponsiveContainer, ReferenceLine } = Recharts;
const MO = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
const MD = [31,28,31,30,31,30,31,31,30,31,30,31];
const SEA = {
sponge: [0.50,0.50,0.60,0.80,1.50,2.00,2.00,1.60,1.10,0.80,1.00,0.50],
peak: [1.15,1.20,1.00,0.85,0.90,1.00,1.00,0.95,0.85,0.90,1.00,1.15],
offPk: [0.75,0.75,0.85,1.00,1.25,1.40,1.40,1.30,1.10,0.95,1.00,0.75],
feedIn: [1.35,1.25,1.05,0.70,0.35,0.25,0.28,0.40,0.65,0.85,1.00,1.35],
};
const BAT = {
peakR: [0.80,0.78,0.68,0.52,0.32,0.25,0.28,0.35,0.48,0.58,0.70,0.78],
offPkR: [0.55,0.52,0.42,0.32,0.20,0.15,0.18,0.22,0.32,0.40,0.48,0.55],
spongeR: [0.10,0.10,0.05,0.00,-0.10,-0.15,-0.15,-0.10,0.00,0.05,0.10,0.10],
feedInR: [0.65,0.62,0.55,0.45,0.30,0.25,0.28,0.35,0.42,0.50,0.60,0.65],
amberSpike: [150,120,60,30,20,40,40,30,20,30,50,100],
};
const fmt = v => `$${Math.round(v).toLocaleString("en-AU")}`;
const fmt2 = v => `$${v.toFixed(2)}`;
const pct = (v, d = 0) => `${v.toFixed(d)}%`;
/* ── Historical ROI Data (embedded) ── */
const HISTORICAL_ROI_DATA = {"battery_spec":{"capacity_kwh":33.28,"usable_kwh":32,"cost":10700,"rebate":1500,"net_cost":9200},"annual_no_sharer":{"cost_no_battery":3124.47,"cost_with_battery":1552.09,"savings":1572.38,"payback_years":5.85},"annual_with_sharer":{"cost_no_battery":3124.47,"cost_with_battery":1552.09,"savings":1572.38,"payback_years":5.85},"monthly_results":[{"month":"2024-10","solar_total":798.15,"consumption":454.38,"cost_no_battery":100.62,"cost_with_battery":5.5,"savings":95.13,"savings_with_sharer":95.13},{"month":"2024-11","solar_total":393.59,"consumption":106.92,"cost_no_battery":124.6,"cost_with_battery":-32.23,"savings":156.82,"savings_with_sharer":156.82},{"month":"2024-12","solar_total":973.95,"consumption":733.1,"cost_no_battery":151.49,"cost_with_battery":23.91,"savings":127.58,"savings_with_sharer":127.58},{"month":"2025-1","solar_total":981.01,"consumption":960.79,"cost_no_battery":208.45,"cost_with_battery":65.92,"savings":142.53,"savings_with_sharer":142.53},{"month":"2025-2","solar_total":824.45,"consumption":820.25,"cost_no_battery":181.83,"cost_with_battery":63.7,"savings":118.12,"savings_with_sharer":118.12},{"month":"2025-3","solar_total":712.69,"consumption":731.91,"cost_no_battery":193.81,"cost_with_battery":69.55,"savings":124.26,"savings_with_sharer":124.26},{"month":"2025-4","solar_total":488.66,"consumption":648.84,"cost_no_battery":194.92,"cost_with_battery":81.5,"savings":113.42,"savings_with_sharer":113.42},{"month":"2025-5","solar_total":399.25,"consumption":1033.06,"cost_no_battery":409.96,"cost_with_battery":296.94,"savings":113.01,"savings_with_sharer":113.01},{"month":"2025-6","solar_total":288.4,"consumption":1021.72,"cost_no_battery":446.58,"cost_with_battery":346.07,"savings":100.51,"savings_with_sharer":100.51},{"month":"2025-7","solar_total":314.06,"consumption":1051.1,"cost_no_battery":472.33,"cost_with_battery":345.39,"savings":126.94,"savings_with_sharer":126.94},{"month":"2025-8","solar_total":435.97,"consumption":910.71,"cost_no_battery":380.93,"cost_with_battery":216.13,"savings":164.8,"savings_with_sharer":164.8},{"month":"2025-9","solar_total":613.99,"consumption":701.57,"cost_no_battery":258.95,"cost_with_battery":69.71,"savings":189.25,"savings_with_sharer":189.25}],"daily_charging":{"total_days":381,"days_full":103,"pct_days_full":27.0,"avg_time_to_full":"15:46","earliest_full":"14:49","latest_full":"18:57","hourly_soc":{"4":0,"5":0.01,"6":0.08,"7":0.28,"8":0.84,"9":1.98,"10":3.88,"11":6.43,"12":9.35,"13":12.42,"14":15.4,"15":17.61,"16":18.56,"17":18.81,"18":21.33,"19":25.03,"20":26.49},"seasons":{"Summer":{"total_days":90,"days_full":74,"pct_days_full":82.2,"avg_solar":30.88,"avg_max_soc":26.02,"avg_time_to_full":"15:46"},"Autumn":{"total_days":92,"days_full":0,"pct_days_full":0.0,"avg_solar":17.4,"avg_max_soc":16.6,"avg_time_to_full":null},"Winter":{"total_days":92,"days_full":0,"pct_days_full":0.0,"avg_solar":11.29,"avg_max_soc":10.83,"avg_time_to_full":null},"Spring":{"total_days":107,"days_full":29,"pct_days_full":27.1,"avg_solar":23.68,"avg_max_soc":21.59,"avg_time_to_full":"15:45"}}},"daily_results":[{"date":"2024-10-01","day_of_week":"Tuesday","total_solar_kwh":24.08,"max_battery_soc_kwh":22.02,"battery_filled_pct":80.5,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.04,"7":0.37,"8":1.11,"9":2.52,"10":4.36,"11":6.98,"12":10.19,"13":13.71,"14":17.8,"15":20.48,"16":21.76,"17":21.97,"18":22.01}},{"date":"2024-10-02","day_of_week":"Wednesday","total_solar_kwh":26.52,"max_battery_soc_kwh":24.9,"battery_filled_pct":91.0,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.05,"7":0.26,"8":0.78,"9":2.29,"10":4.98,"11":8.5,"12":12.54,"13":16.66,"14":20.75,"15":23.39,"16":24.64,"17":24.86,"18":24.9}},{"date":"2024-10-03","day_of_week":"Thursday","total_solar_kwh":19.84,"max_battery_soc_kwh":18.56,"battery_filled_pct":67.9,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.06,"7":0.35,"8":0.99,"9":2.45,"10":4.8,"11":7.29,"12":10.85,"13":14.09,"14":15.96,"15":17.46,"16":18.32,"17":18.54,"18":18.56}},{"date":"2024-10-04","day_of_week":"Friday","total_solar_kwh":27.53,"max_battery_soc_kwh":25.4,"battery_filled_pct":92.8,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.07,"7":0.49,"8":1.53,"9":3.47,"10":6.4,"11":9.74,"12":13.35,"13":17.21,"14":20.65,"15":23.06,"16":24.82,"17":25.33,"18":25.4}},{"date":"2024-10-05","day_of_week":"Saturday","total_solar_kwh":23.01,"max_battery_soc_kwh":21.15,"battery_filled_pct":77.3,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.13,"7":0.64,"8":1.34,"9":2.39,"10":4.08,"11":6.86,"12":9.52,"13":13.09,"14":16.54,"15":19.19,"16":20.52,"17":21.06,"18":21.14}},{"date":"2024-10-06","day_of_week":"Sunday","total_solar_kwh":20.66,"max_battery_soc_kwh":19.52,"battery_filled_pct":71.4,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.06,"7":0.36,"8":0.98,"9":2.31,"10":3.99,"11":6.11,"12":8.93,"13":11.95,"14":15.21,"15":17.76,"16":19.18,"17":19.46,"18":19.52}},{"date":"2024-10-07","day_of_week":"Monday","total_solar_kwh":23.96,"max_battery_soc_kwh":22.38,"battery_filled_pct":81.8,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.08,"7":0.5,"8":1.33,"9":2.88,"10":5.71,"11":8.35,"12":11.14,"13":14.28,"14":17.91,"15":20.65,"16":22.04,"17":22.31,"18":22.38}},{"date":"2024-10-08","day_of_week":"Tuesday","total_solar_kwh":28.93,"max_battery_soc_kwh":26.48,"battery_filled_pct":96.8,"time_to_full":"16:05","hourly_soc":{"5":0.0,"6":0.07,"7":0.37,"8":1.07,"9":2.78,"10":5.81,"11":9.7,"12":13.8,"13":17.93,"14":22.03,"15":24.84,"16":26.23,"17":26.43,"18":26.47}},{"date":"2024-10-09","day_of_week":"Wednesday","total_solar_kwh":28.42,"max_battery_soc_kwh":26.11,"battery_filled_pct":95.4,"time_to_full":"17:01","hourly_soc":{"5":0.0,"6":0.07,"7":0.32,"8":0.96,"9":2.7,"10":5.63,"11":9.39,"12":13.5,"13":17.63,"14":21.73,"15":24.48,"16":25.83,"17":26.06,"18":26.1}},{"date":"2024-10-10","day_of_week":"Thursday","total_solar_kwh":29.14,"max_battery_soc_kwh":26.56,"battery_filled_pct":97.1,"time_to_full":"16:11","hourly_soc":{"5":0.0,"6":0.06,"7":0.34,"8":1.04,"9":2.81,"10":5.76,"11":9.52,"12":13.63,"13":17.76,"14":21.86,"15":24.72,"16":26.18,"17":26.48,"18":26.55}},{"date":"2024-10-11","day_of_week":"Friday","total_solar_kwh":28.5,"max_battery_soc_kwh":26.34,"battery_filled_pct":96.3,"time_to_full":"16:21","hourly_soc":{"5":0.0,"6":0.07,"7":0.37,"8":1.08,"9":2.87,"10":5.8,"11":9.55,"12":13.67,"13":17.79,"14":21.8,"15":24.54,"16":26.01,"17":26.28,"18":26.34}},{"date":"2024-10-12","day_of_week":"Saturday","total_solar_kwh":26.54,"max_battery_soc_kwh":24.99,"battery_filled_pct":91.3,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.09,"7":0.44,"8":1.25,"9":3.12,"10":6.12,"11":9.88,"12":13.73,"13":17.08,"14":20.86,"15":23.18,"16":24.27,"17":24.85,"18":24.98}},{"date":"2024-10-13","day_of_week":"Sunday","total_solar_kwh":14.88,"max_battery_soc_kwh":14.22,"battery_filled_pct":52.0,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.01,"7":0.22,"8":0.9,"9":2.01,"10":3.84,"11":6.48,"12":9.03,"13":10.93,"14":12.21,"15":12.94,"16":13.62,"17":14.13,"18":14.22}},{"date":"2024-10-14","day_of_week":"Monday","total_solar_kwh":25.19,"max_battery_soc_kwh":23.27,"battery_filled_pct":85.1,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.1,"7":0.49,"8":1.24,"9":2.48,"10":4.67,"11":7.4,"12":11.43,"13":15.52,"14":19.31,"15":21.3,"16":22.78,"17":23.16,"18":23.27}},{"date":"2024-10-15","day_of_week":"Tuesday","total_solar_kwh":24.88,"max_battery_soc_kwh":23.55,"battery_filled_pct":86.1,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.08,"7":0.3,"8":1.22,"9":3.05,"10":5.78,"11":9.36,"12":13.01,"13":16.19,"14":19.32,"15":21.57,"16":23.17,"17":23.45,"18":23.55}},{"date":"2024-10-16","day_of_week":"Wednesday","total_solar_kwh":20.51,"max_battery_soc_kwh":19.22,"battery_filled_pct":70.2,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.09,"7":0.51,"8":1.22,"9":2.31,"10":4.09,"11":6.29,"12":9.98,"13":12.97,"14":15.35,"15":17.35,"16":18.6,"17":19.1,"18":19.21}},{"date":"2024-10-17","day_of_week":"Thursday","total_solar_kwh":12.64,"max_battery_soc_kwh":11.78,"battery_filled_pct":43.1,"time_to_full":null,"hourly_soc":{"5":0.01,"6":0.1,"7":0.39,"8":0.91,"9":2.22,"10":3.82,"11":4.8,"12":5.75,"13":8.56,"14":10.63,"15":11.2,"16":11.56,"17":11.72,"18":11.78}},{"date":"2024-10-18","day_of_week":"Friday","total_solar_kwh":13.44,"max_battery_soc_kwh":12.71,"battery_filled_pct":46.5,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.04,"7":0.36,"8":0.81,"9":1.54,"10":2.32,"11":3.07,"12":4.47,"13":6.67,"14":9.15,"15":10.88,"16":12.27,"17":12.63,"18":12.7,"19":12.71}},{"date":"2024-10-19","day_of_week":"Saturday","total_solar_kwh":30.54,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:42","hourly_soc":{"5":0.01,"6":0.15,"7":0.49,"8":1.32,"9":3.32,"10":6.45,"11":10.34,"12":14.47,"13":18.6,"14":22.71,"15":25.63,"16":27.18,"17":27.36,"18":27.36}},{"date":"2024-10-20","day_of_week":"Sunday","total_solar_kwh":28.31,"max_battery_soc_kwh":26.07,"battery_filled_pct":95.3,"time_to_full":"17:27","hourly_soc":{"5":0.01,"6":0.11,"7":0.44,"8":1.34,"9":3.28,"10":6.36,"11":10.02,"12":13.97,"13":17.36,"14":21.32,"15":24.16,"16":25.66,"17":26.0,"18":26.07}},{"date":"2024-10-21","day_of_week":"Monday","total_solar_kwh":27.38,"max_battery_soc_kwh":25.73,"battery_filled_pct":94.0,"time_to_full":null,"hourly_soc":{"5":0.01,"6":0.27,"7":0.76,"8":1.77,"9":3.76,"10":6.58,"11":10.36,"12":13.91,"13":17.52,"14":20.97,"15":23.65,"16":25.23,"17":25.64,"18":25.72}},{"date":"2024-10-22","day_of_week":"Tuesday","total_solar_kwh":18.87,"max_battery_soc_kwh":18.07,"battery_filled_pct":66.1,"time_to_full":null,"hourly_soc":{"5":0.01,"6":0.16,"7":0.79,"8":1.88,"9":3.41,"10":5.37,"11":7.64,"12":10.45,"13":12.67,"14":14.71,"15":16.38,"16":17.56,"17":18.01,"18":18.07}},{"date":"2024-10-23","day_of_week":"Wednesday","total_solar_kwh":32.9,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:03","hourly_soc":{"5":0.01,"6":0.16,"7":0.75,"8":2.15,"9":4.72,"10":8.0,"11":12.01,"12":16.14,"13":20.27,"14":24.26,"15":26.97,"16":27.36,"17":27.36,"18":27.36,"19":27.36}},{"date":"2024-10-24","day_of_week":"Thursday","total_solar_kwh":31.47,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:38","hourly_soc":{"5":0.01,"6":0.21,"7":0.73,"8":1.65,"9":3.37,"10":6.46,"11":10.32,"12":14.45,"13":18.58,"14":22.69,"15":25.71,"16":27.27,"17":27.36,"18":27.36,"19":27.36}},{"date":"2024-10-25","day_of_week":"Friday","total_solar_kwh":29.48,"max_battery_soc_kwh":27.07,"battery_filled_pct":98.9,"time_to_full":"16:13","hourly_soc":{"5":0.01,"6":0.13,"7":0.56,"8":1.63,"9":3.73,"10":6.97,"11":10.8,"12":14.16,"13":17.91,"14":21.86,"15":24.76,"16":26.3,"17":26.87,"18":27.06,"19":27.07}},{"date":"2024-10-26","day_of_week":"Saturday","total_solar_kwh":27.22,"max_battery_soc_kwh":24.77,"battery_filled_pct":90.5,"time_to_full":null,"hourly_soc":{"5":0.01,"6":0.18,"7":0.82,"8":1.86,"9":3.37,"10":5.74,"11":9.27,"12":12.57,"13":16.44,"14":20.52,"15":23.19,"16":24.27,"17":24.66,"18":24.77,"19":24.77}},{"date":"2024-10-27","day_of_week":"Sunday","total_solar_kwh":30.89,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:44","hourly_soc":{"5":0.01,"6":0.18,"7":0.53,"8":1.36,"9":3.45,"10":6.54,"11":10.4,"12":14.39,"13":18.51,"14":22.63,"15":25.63,"16":27.23,"17":27.36,"18":27.36,"19":27.36}},{"date":"2024-10-28","day_of_week":"Monday","total_solar_kwh":32.85,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:04","hourly_soc":{"5":0.02,"6":0.28,"7":0.96,"8":2.31,"9":4.51,"10":7.8,"11":11.78,"12":15.9,"13":20.03,"14":24.15,"15":27.0,"16":27.36,"17":27.36,"18":27.36,"19":27.36}},{"date":"2024-10-29","day_of_week":"Tuesday","total_solar_kwh":31.68,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:24","hourly_soc":{"4":0.0,"5":0.01,"6":0.16,"7":0.52,"8":1.53,"9":3.73,"10":6.95,"11":10.9,"12":15.03,"13":19.16,"14":23.28,"15":26.28,"16":27.36,"17":27.36,"18":27.36,"19":27.36}},{"date":"2024-10-30","day_of_week":"Wednesday","total_solar_kwh":26.04,"max_battery_soc_kwh":24.37,"battery_filled_pct":89.1,"time_to_full":null,"hourly_soc":{"4":0.0,"5":0.01,"6":0.15,"7":0.46,"8":1.46,"9":3.64,"10":6.82,"11":10.56,"12":14.59,"13":17.99,"14":20.15,"15":22.02,"16":23.66,"17":24.21,"18":24.37,"19":24.37}},{"date":"2024-10-31","day_of_week":"Thursday","total_solar_kwh":31.84,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:29","hourly_soc":{"4":0.0,"5":0.01,"6":0.16,"7":0.54,"8":1.62,"9":3.77,"10":6.82,"11":10.78,"12":14.91,"13":19.03,"14":23.16,"15":26.23,"16":27.36,"17":27.36,"18":27.36,"19":27.36}},{"date":"2024-11-01","day_of_week":"Friday","total_solar_kwh":32.21,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:14","hourly_soc":{"4":0.0,"5":0.01,"6":0.16,"7":0.5,"8":1.59,"9":3.9,"10":7.2,"11":11.22,"12":15.35,"13":19.48,"14":23.61,"15":26.63,"16":27.36,"17":27.36,"18":27.36,"19":27.36}},{"date":"2024-11-02","day_of_week":"Saturday","total_solar_kwh":30.3,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:44","hourly_soc":{"4":0.0,"5":0.02,"6":0.27,"7":1.09,"8":2.4,"9":4.51,"10":7.51,"11":11.11,"12":15.04,"13":19.07,"14":22.95,"15":25.68,"16":27.22,"17":27.36,"18":27.36,"19":27.36}},{"date":"2024-11-03","day_of_week":"Sunday","total_solar_kwh":32.73,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:00","hourly_soc":{"4":0.0,"5":0.03,"6":0.29,"7":1.08,"8":2.49,"9":4.72,"10":8.0,"11":12.0,"12":15.92,"13":19.92,"14":24.03,"15":27.04,"16":27.36,"17":27.36,"18":27.36,"19":27.36}},{"date":"2024-11-04","day_of_week":"Monday","total_solar_kwh":31.87,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:25","hourly_soc":{"4":0.0,"5":0.01,"6":0.15,"7":0.77,"8":1.87,"9":3.68,"10":6.66,"11":10.55,"12":14.64,"13":18.71,"14":22.84,"15":26.08,"16":27.35,"17":27.36,"18":27.36,"19":27.36}},{"date":"2024-11-05","day_of_week":"Tuesday","total_solar_kwh":14.86,"max_battery_soc_kwh":14.14,"battery_filled_pct":51.7,"time_to_full":null,"hourly_soc":{"4":0.0,"5":0.03,"6":0.33,"7":0.91,"8":2.11,"9":3.37,"10":4.13,"11":5.54,"12":6.08,"13":7.23,"14":9.22,"15":11.57,"16":13.24,"17":13.86,"18":14.13,"19":14.14}},{"date":"2024-11-06","day_of_week":"Wednesday","total_solar_kwh":26.97,"max_battery_soc_kwh":24.74,"battery_filled_pct":90.4,"time_to_full":null,"hourly_soc":{"4":0.0,"5":0.01,"6":0.23,"7":0.9,"8":1.94,"9":3.46,"10":5.32,"11":8.16,"12":11.67,"13":15.34,"14":19.24,"15":22.3,"16":23.81,"17":24.48,"18":24.72,"19":24.73}},{"date":"2024-11-07","day_of_week":"Thursday","total_solar_kwh":28.13,"max_battery_soc_kwh":25.72,"battery_filled_pct":94.0,"time_to_full":null,"hourly_soc":{"4":0.0,"5":0.01,"6":0.15,"7":0.84,"8":1.97,"9":3.63,"10":6.25,"11":9.87,"12":13.16,"13":16.58,"14":20.0,"15":23.13,"16":25.04,"17":25.6,"18":25.7,"19":25.72}},{"date":"2024-11-08","day_of_week":"Friday","total_solar_kwh":32.61,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:30","hourly_soc":{"4":0.0,"5":0.01,"6":0.21,"7":0.76,"8":1.97,"9":4.01,"10":7.46,"11":11.28,"12":14.46,"13":18.53,"14":22.66,"15":26.01,"16":27.35,"17":27.36,"18":27.36,"19":27.36}},{"date":"2024-11-09","day_of_week":"Saturday","total_solar_kwh":17.56,"max_battery_soc_kwh":16.74,"battery_filled_pct":61.2,"time_to_full":null,"hourly_soc":{"4":0.0,"5":0.01,"6":0.17,"7":0.63,"8":1.34,"9":2.39,"10":3.49,"11":4.68,"12":6.87,"13":9.68,"14":11.61,"15":14.12,"16":16.02,"17":16.58,"18":16.72,"19":16.74}},{"date":"2024-11-10","day_of_week":"Sunday","total_solar_kwh":32.84,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:06","hourly_soc":{"4":0.0,"5":0.03,"6":0.2,"7":0.65,"8":1.82,"9":3.93,"10":7.17,"11":11.17,"12":15.3,"13":19.43,"14":23.55,"15":26.78,"16":27.36,"17":27.36,"18":27.36,"19":27.36}},{"date":"2024-11-11","day_of_week":"Monday","total_solar_kwh":24.97,"max_battery_soc_kwh":23.37,"battery_filled_pct":85.4,"time_to_full":null,"hourly_soc":{"4":0.0,"5":0.04,"6":0.31,"7":0.94,"8":2.38,"9":4.65,"10":7.74,"11":10.77,"12":13.53,"13":15.83,"14":19.24,"15":21.41,"16":22.62,"17":23.07,"18":23.34,"19":23.37}},{"date":"2024-11-12","day_of_week":"Tuesday","total_solar_kwh":33.28,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:04","hourly_soc":{"4":0.0,"5":0.03,"6":0.23,"7":0.63,"8":1.8,"9":4.11,"10":7.44,"11":11.44,"12":15.56,"13":19.69,"14":23.82,"15":26.93,"16":27.36,"17":27.36,"18":27.36,"19":27.36}},{"date":"2024-11-13","day_of_week":"Wednesday","total_solar_kwh":33.63,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:15","hourly_soc":{"4":0.0,"5":0.03,"6":0.34,"7":0.88,"8":2.06,"9":3.8,"10":6.69,"11":10.69,"12":14.81,"13":18.94,"14":23.07,"15":26.52,"16":27.36,"17":27.36,"18":27.36,"19":27.36}},{"date":"2024-11-14","day_of_week":"Thursday","total_solar_kwh":10.15,"max_battery_soc_kwh":9.46,"battery_filled_pct":34.6,"time_to_full":null,"hourly_soc":{"4":0.0,"5":0.04,"6":0.4,"7":1.19,"8":2.33,"9":4.15,"10":6.88,"11":8.91}},{"date":"2024-11-30","day_of_week":"Saturday","total_solar_kwh":11.47,"max_battery_soc_kwh":10.01,"battery_filled_pct":36.6,"time_to_full":null,"hourly_soc":{"13":0.69,"14":3.23,"15":6.82,"16":9.01,"17":9.86,"18":9.98,"19":10.01}},{"date":"2024-12-01","day_of_week":"Sunday","total_solar_kwh":35.82,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"14:54","hourly_soc":{"4":0.0,"5":0.04,"6":0.29,"7":0.78,"8":2.06,"9":4.71,"10":8.37,"11":12.42,"12":16.48,"13":20.6,"14":24.73,"15":27.32,"16":27.36,"17":27.36,"18":27.36,"19":27.36}},{"date":"2024-12-02","day_of_week":"Monday","total_solar_kwh":20.73,"max_battery_soc_kwh":19.84,"battery_filled_pct":72.5,"time_to_full":null,"hourly_soc":{"4":0.0,"5":0.1,"6":0.47,"7":1.12,"8":2.46,"9":4.86,"10":8.26,"11":11.78,"12":14.72,"13":17.41,"14":18.72,"15":19.23,"16":19.45,"17":19.73,"18":19.82,"19":19.84}},{"date":"2024-12-03","day_of_week":"Tuesday","total_solar_kwh":32.02,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"16:19","hourly_soc":{"4":0.0,"5":0.01,"6":0.13,"7":0.32,"8":0.74,"9":1.51,"10":4.5,"11":8.35,"12":12.33,"13":16.46,"14":20.58,"15":24.25,"16":26.48,"17":27.35,"18":27.36,"19":27.36}},{"date":"2024-12-04","day_of_week":"Wednesday","total_solar_kwh":33.97,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:10","hourly_soc":{"4":0.0,"5":0.03,"6":0.22,"7":0.61,"8":1.88,"9":4.35,"10":7.85,"11":11.91,"12":16.04,"13":19.82,"14":23.44,"15":26.82,"16":27.36,"17":27.36,"18":27.36,"19":27.36}},{"date":"2024-12-05","day_of_week":"Thursday","total_solar_kwh":6.56,"max_battery_soc_kwh":6.17,"battery_filled_pct":22.5,"time_to_full":null,"hourly_soc":{"4":0.0,"14":0.55,"15":2.99,"16":5.07,"17":6.02,"18":6.14,"19":6.16}},{"date":"2024-12-06","day_of_week":"Friday","total_solar_kwh":19.4,"max_battery_soc_kwh":18.6,"battery_filled_pct":68.0,"time_to_full":null,"hourly_soc":{"4":0.0,"5":0.01,"6":0.25,"7":0.92,"8":1.91,"9":3.38,"10":5.41,"11":8.39,"12":10.64,"13":12.24,"14":14.57,"15":16.13,"16":17.15,"17":18.01,"18":18.51,"19":18.59}},{"date":"2024-12-07","day_of_week":"Saturday","total_solar_kwh":36.2,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"14:51","hourly_soc":{"4":0.0,"5":0.04,"6":0.3,"7":0.9,"8":2.17,"9":4.6,"10":8.08,"11":12.14,"12":16.27,"13":20.39,"14":24.52,"15":27.29,"16":27.36,"17":27.36,"18":27.36,"19":27.36}},{"date":"2024-12-08","day_of_week":"Sunday","total_solar_kwh":34.08,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:16","hourly_soc":{"4":0.0,"5":0.04,"6":0.42,"7":1.0,"8":2.56,"9":4.91,"10":8.38,"11":12.43,"12":16.26,"13":19.51,"14":23.31,"15":26.74,"16":27.36,"17":27.36,"18":27.36,"19":27.36}},{"date":"2024-12-09","day_of_week":"Monday","total_solar_kwh":32.97,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:26","hourly_soc":{"4":0.0,"5":0.01,"6":0.14,"7":0.72,"8":1.88,"9":3.88,"10":6.41,"11":10.23,"12":14.2,"13":18.2,"14":22.33,"15":26.07,"16":27.36,"17":27.36,"18":27.36,"19":27.36}},{"date":"2024-12-10","day_of_week":"Tuesday","total_solar_kwh":36.48,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"14:49","hourly_soc":{"4":0.0,"5":0.05,"6":0.37,"7":1.05,"8":2.4,"9":4.78,"10":8.23,"11":12.27,"12":16.4,"13":20.53,"14":24.83,"15":27.35,"16":27.36,"17":27.36,"18":27.36,"19":27.36}},{"date":"2024-12-11","day_of_week":"Wednesday","total_solar_kwh":36.37,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"14:54","hourly_soc":{"4":0.0,"5":0.05,"6":0.34,"7":0.83,"8":2.14,"9":4.63,"10":8.2,"11":12.29,"12":16.42,"13":20.55,"14":24.68,"15":27.31,"16":27.36,"17":27.36,"18":27.36,"19":27.36}},{"date":"2024-12-12","day_of_week":"Thursday","total_solar_kwh":35.75,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"14:59","hourly_soc":{"4":0.0,"5":0.05,"6":0.29,"7":0.73,"8":1.99,"9":4.42,"10":7.9,"11":11.97,"12":16.1,"13":20.23,"14":24.36,"15":27.25,"16":27.36,"17":27.36,"18":27.36,"19":27.36}},{"date":"2024-12-13","day_of_week":"Friday","total_solar_kwh":36.0,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"14:59","hourly_soc":{"4":0.0,"5":0.03,"6":0.22,"7":0.74,"8":2.03,"9":4.45,"10":7.96,"11":12.03,"12":16.16,"13":20.29,"14":24.42,"15":27.27,"16":27.36,"17":27.36,"18":27.36,"19":27.36}},{"date":"2024-12-14","day_of_week":"Saturday","total_solar_kwh":23.27,"max_battery_soc_kwh":22.22,"battery_filled_pct":81.2,"time_to_full":null,"hourly_soc":{"4":0.0,"5":0.07,"6":0.46,"7":1.18,"8":2.51,"9":4.75,"10":7.63,"11":9.7,"12":11.67,"13":14.28,"14":17.1,"15":19.13,"16":20.73,"17":21.66,"18":22.15,"19":22.21}},{"date":"2024-12-15","day_of_week":"Sunday","total_solar_kwh":29.59,"max_battery_soc_kwh":27.13,"battery_filled_pct":99.2,"time_to_full":"16:54","hourly_soc":{"4":0.0,"5":0.05,"6":0.27,"7":0.78,"8":2.05,"9":4.38,"10":7.09,"11":9.94,"12":13.88,"13":17.88,"14":21.19,"15":23.29,"16":25.47,"17":26.59,"18":27.03,"19":27.13}},{"date":"2024-12-16","day_of_week":"Monday","total_solar_kwh":30.01,"max_battery_soc_kwh":27.24,"battery_filled_pct":99.6,"time_to_full":"16:54","hourly_soc":{"4":0.0,"5":0.04,"6":0.23,"7":0.62,"8":1.79,"9":3.62,"10":6.0,"11":9.53,"12":13.49,"13":17.4,"14":20.25,"15":23.45,"16":25.34,"17":26.75,"18":27.18,"19":27.23}},{"date":"2024-12-17","day_of_week":"Tuesday","total_solar_kwh":36.66,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"14:54","hourly_soc":{"4":0.0,"5":0.05,"6":0.38,"7":0.88,"8":1.94,"9":4.5,"10":8.06,"11":12.17,"12":16.29,"13":20.42,"14":24.55,"15":27.29,"16":27.36,"17":27.36,"18":27.36,"19":27.36,"20":27.36}},{"date":"2024-12-18","day_of_week":"Wednesday","total_solar_kwh":35.49,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:00","hourly_soc":{"4":0.0,"5":0.03,"6":0.21,"7":0.58,"8":1.78,"9":4.16,"10":7.6,"11":11.65,"12":15.78,"13":19.91,"14":24.03,"15":27.17,"16":27.36,"17":27.36,"18":27.36,"19":27.36,"20":27.36}},{"date":"2024-12-19","day_of_week":"Thursday","total_solar_kwh":35.66,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:05","hourly_soc":{"4":0.0,"5":0.03,"6":0.19,"7":0.56,"8":1.72,"9":4.02,"10":7.33,"11":11.31,"12":15.44,"13":19.57,"14":23.7,"15":27.05,"16":27.36,"17":27.36,"18":27.36,"19":27.36,"20":27.36}},{"date":"2024-12-20","day_of_week":"Friday","total_solar_kwh":36.04,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:00","hourly_soc":{"4":0.0,"5":0.04,"6":0.21,"7":0.57,"8":1.69,"9":3.96,"10":7.38,"11":11.44,"12":15.56,"13":19.69,"14":23.82,"15":27.1,"16":27.36,"17":27.36,"18":27.36,"19":27.36,"20":27.36}},{"date":"2024-12-21","day_of_week":"Saturday","total_solar_kwh":36.28,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:00","hourly_soc":{"4":0.0,"5":0.03,"6":0.21,"7":0.61,"8":1.79,"9":4.15,"10":7.58,"11":11.64,"12":15.77,"13":19.9,"14":24.03,"15":27.17,"16":27.36,"17":27.36,"18":27.36,"19":27.36,"20":27.36}},{"date":"2024-12-22","day_of_week":"Sunday","total_solar_kwh":35.86,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:00","hourly_soc":{"4":0.0,"5":0.03,"6":0.2,"7":0.59,"8":1.83,"9":4.19,"10":7.66,"11":11.72,"12":15.78,"13":19.91,"14":24.03,"15":27.17,"16":27.36,"17":27.36,"18":27.36,"19":27.36,"20":27.36}},{"date":"2024-12-23","day_of_week":"Monday","total_solar_kwh":33.95,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:40","hourly_soc":{"4":0.0,"5":0.04,"6":0.31,"7":0.85,"8":1.68,"9":3.3,"10":6.14,"11":9.05,"12":13.16,"13":17.28,"14":21.38,"15":25.33,"16":27.29,"17":27.36,"18":27.36,"19":27.36,"20":27.36}},{"date":"2024-12-24","day_of_week":"Tuesday","total_solar_kwh":35.81,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:01","hourly_soc":{"4":0.0,"5":0.03,"6":0.2,"7":0.57,"8":1.71,"9":4.01,"10":7.37,"11":11.39,"12":15.51,"13":19.64,"14":23.77,"15":27.08,"16":27.36,"17":27.36,"18":27.36,"19":27.36,"20":27.36}},{"date":"2024-12-25","day_of_week":"Wednesday","total_solar_kwh":35.14,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:06","hourly_soc":{"4":0.0,"5":0.03,"6":0.19,"7":0.52,"8":1.61,"9":3.84,"10":7.12,"11":11.09,"12":15.22,"13":19.35,"14":23.48,"15":26.96,"16":27.36,"17":27.36,"18":27.36,"19":27.36}},{"date":"2024-12-26","day_of_week":"Thursday","total_solar_kwh":16.65,"max_battery_soc_kwh":15.37,"battery_filled_pct":56.2,"time_to_full":null,"hourly_soc":{"4":0.0,"5":0.02,"6":0.16,"7":0.27,"8":0.66,"9":1.35,"10":2.91,"11":4.71,"12":6.5,"13":8.69,"14":11.61,"15":13.03,"16":14.02,"17":14.77,"18":15.24,"19":15.37,"20":15.37}},{"date":"2024-12-27","day_of_week":"Friday","total_solar_kwh":30.21,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"16:45","hourly_soc":{"4":0.0,"5":0.03,"6":0.3,"7":1.02,"8":2.46,"9":4.54,"10":7.16,"11":10.83,"12":14.95,"13":18.32,"14":20.78,"15":23.8,"16":25.66,"17":27.07,"18":27.36,"19":27.36,"20":27.36}},{"date":"2024-12-28","day_of_week":"Saturday","total_solar_kwh":25.44,"max_battery_soc_kwh":23.24,"battery_filled_pct":84.9,"time_to_full":null,"hourly_soc":{"4":0.0,"5":0.02,"6":0.18,"7":0.76,"8":1.72,"9":2.79,"10":4.22,"11":7.07,"12":11.05,"13":13.82,"14":16.31,"15":19.68,"16":21.78,"17":22.95,"18":23.17,"19":23.24,"20":23.24}},{"date":"2024-12-29","day_of_week":"Sunday","total_solar_kwh":34.16,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:34","hourly_soc":{"4":0.0,"5":0.06,"6":0.33,"7":0.87,"8":2.19,"9":3.66,"10":5.89,"11":9.44,"12":13.57,"13":17.7,"14":21.83,"15":25.73,"16":27.35,"17":27.36,"18":27.36,"19":27.36,"20":27.36}},{"date":"2024-12-30","day_of_week":"Monday","total_solar_kwh":32.02,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:35","hourly_soc":{"4":0.0,"5":0.04,"6":0.37,"7":0.98,"8":2.26,"9":4.37,"10":7.35,"11":11.15,"12":14.59,"13":18.32,"14":22.32,"15":25.71,"16":27.29,"17":27.36,"18":27.36,"19":27.36,"20":27.36}},{"date":"2024-12-31","day_of_week":"Tuesday","total_solar_kwh":35.35,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:10","hourly_soc":{"4":0.0,"5":0.03,"6":0.22,"7":0.6,"8":1.64,"9":3.84,"10":7.14,"11":11.13,"12":15.08,"13":19.04,"14":23.17,"15":26.81,"16":27.36,"17":27.36,"18":27.36,"19":27.36,"20":27.36}},{"date":"2025-01-01","day_of_week":"Wednesday","total_solar_kwh":36.18,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:06","hourly_soc":{"4":0.0,"5":0.02,"6":0.18,"7":0.52,"8":1.59,"9":3.86,"10":7.23,"11":11.27,"12":15.39,"13":19.52,"14":23.64,"15":27.0,"16":27.36,"17":27.36,"18":27.36,"19":27.36,"20":27.36}},{"date":"2025-01-02","day_of_week":"Thursday","total_solar_kwh":35.94,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:05","hourly_soc":{"4":0.0,"5":0.03,"6":0.23,"7":0.63,"8":1.69,"9":3.93,"10":7.24,"11":11.24,"12":15.37,"13":19.5,"14":23.63,"15":27.02,"16":27.36,"17":27.36,"18":27.36,"19":27.36,"20":27.36}},{"date":"2025-01-03","day_of_week":"Friday","total_solar_kwh":35.25,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:10","hourly_soc":{"4":0.0,"5":0.02,"6":0.21,"7":0.58,"8":1.59,"9":3.76,"10":7.02,"11":10.98,"12":15.11,"13":19.24,"14":23.37,"15":26.91,"16":27.36,"17":27.36,"18":27.36,"19":27.36}},{"date":"2025-01-04","day_of_week":"Saturday","total_solar_kwh":18.97,"max_battery_soc_kwh":18.17,"battery_filled_pct":66.4,"time_to_full":null,"hourly_soc":{"4":0.0,"5":0.02,"6":0.25,"7":0.95,"8":2.33,"9":4.13,"10":6.54,"11":8.98,"12":11.02,"13":13.7,"14":15.33,"15":16.45,"16":17.22,"17":17.76,"18":18.08,"19":18.17}},{"date":"2025-01-05","day_of_week":"Sunday","total_solar_kwh":14.69,"max_battery_soc_kwh":14.05,"battery_filled_pct":51.3,"time_to_full":null,"hourly_soc":{"4":0.0,"5":0.02,"6":0.24,"7":0.96,"8":2.21,"9":3.07,"10":4.61,"11":6.0,"12":7.69,"13":9.67,"14":11.65,"15":12.71,"16":13.39,"17":13.8,"18":14.0,"19":14.04}},{"date":"2025-01-06","day_of_week":"Monday","total_solar_kwh":25.14,"max_battery_soc_kwh":23.18,"battery_filled_pct":84.7,"time_to_full":null,"hourly_soc":{"5":0.01,"6":0.16,"7":0.66,"8":1.71,"9":3.43,"10":6.19,"11":9.07,"12":11.84,"13":14.66,"14":16.93,"15":19.55,"16":21.3,"17":22.55,"18":23.09,"19":23.17,"20":23.18}},{"date":"2025-01-07","day_of_week":"Tuesday","total_solar_kwh":36.04,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:06","hourly_soc":{"4":0.0,"5":0.02,"6":0.18,"7":0.5,"8":1.52,"9":3.78,"10":7.17,"11":11.2,"12":15.33,"13":19.46,"14":23.59,"15":27.01,"16":27.36,"17":27.36,"18":27.36,"19":27.36,"20":27.36}},{"date":"2025-01-08","day_of_week":"Wednesday","total_solar_kwh":34.09,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:21","hourly_soc":{"4":0.0,"5":0.01,"6":0.16,"7":0.46,"8":1.42,"9":3.52,"10":6.7,"11":10.58,"12":14.66,"13":18.77,"14":22.85,"15":26.53,"16":27.36,"17":27.36,"18":27.36,"19":27.36}},{"date":"2025-01-09","day_of_week":"Thursday","total_solar_kwh":33.12,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:41","hourly_soc":{"5":0.01,"6":0.08,"7":0.34,"8":0.92,"9":2.05,"10":4.96,"11":8.96,"12":13.08,"13":17.21,"14":21.34,"15":25.32,"16":27.29,"17":27.36,"18":27.36,"19":27.36,"20":27.36}},{"date":"2025-01-10","day_of_week":"Friday","total_solar_kwh":34.59,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:16","hourly_soc":{"4":0.0,"5":0.02,"6":0.16,"7":0.48,"8":1.45,"9":3.48,"10":6.55,"11":10.45,"12":14.58,"13":18.71,"14":22.84,"15":26.63,"16":27.36,"17":27.36,"18":27.36,"19":27.36,"20":27.36}},{"date":"2025-01-11","day_of_week":"Saturday","total_solar_kwh":34.94,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:12","hourly_soc":{"4":0.0,"5":0.02,"6":0.28,"7":1.02,"8":2.1,"9":4.17,"10":7.07,"11":10.84,"12":14.95,"13":19.08,"14":23.21,"15":26.78,"16":27.36,"17":27.36,"18":27.36,"19":27.36}},{"date":"2025-01-12","day_of_week":"Sunday","total_solar_kwh":34.64,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:22","hourly_soc":{"5":0.01,"6":0.12,"7":0.47,"8":1.37,"9":3.37,"10":6.43,"11":10.31,"12":14.44,"13":18.56,"14":22.69,"15":26.54,"16":27.36,"17":27.36,"18":27.36,"19":27.36,"20":27.36}},{"date":"2025-01-13","day_of_week":"Monday","total_solar_kwh":35.26,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:12","hourly_soc":{"4":0.0,"5":0.01,"6":0.14,"7":0.65,"8":1.72,"9":3.72,"10":6.84,"11":10.77,"12":14.9,"13":19.03,"14":23.15,"15":26.8,"16":27.36,"17":27.36,"18":27.36,"19":27.36,"20":27.36}},{"date":"2025-01-14","day_of_week":"Tuesday","total_solar_kwh":34.59,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:17","hourly_soc":{"4":0.0,"5":0.01,"6":0.19,"7":0.74,"8":1.84,"9":3.73,"10":6.86,"11":10.79,"12":14.78,"13":18.85,"14":22.98,"15":26.69,"16":27.36,"17":27.36,"18":27.36,"19":27.36}},{"date":"2025-01-15","day_of_week":"Wednesday","total_solar_kwh":33.13,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"16:02","hourly_soc":{"5":0.0,"6":0.15,"7":0.58,"8":1.52,"9":3.15,"10":5.29,"11":8.2,"12":12.23,"13":16.36,"14":20.46,"15":24.43,"16":26.92,"17":27.36,"18":27.36,"19":27.36,"20":27.36}},{"date":"2025-01-16","day_of_week":"Thursday","total_solar_kwh":28.22,"max_battery_soc_kwh":26.02,"battery_filled_pct":95.1,"time_to_full":"18:57","hourly_soc":{"4":0.0,"5":0.01,"6":0.18,"7":0.62,"8":1.15,"9":2.15,"10":4.38,"11":7.67,"12":10.86,"13":14.26,"14":17.93,"15":21.63,"16":24.12,"17":25.6,"18":25.95,"19":26.01,"20":26.02}},{"date":"2025-01-17","day_of_week":"Friday","total_solar_kwh":33.28,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:33","hourly_soc":{"4":0.0,"5":0.01,"6":0.12,"7":0.39,"8":1.26,"9":3.2,"10":6.48,"11":10.21,"12":13.82,"13":17.89,"14":22.02,"15":25.98,"16":27.36,"17":27.36,"18":27.36,"19":27.36,"20":27.36}},{"date":"2025-01-18","day_of_week":"Saturday","total_solar_kwh":34.03,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:23","hourly_soc":{"5":0.01,"6":0.14,"7":0.39,"8":1.22,"9":3.18,"10":6.22,"11":10.06,"12":14.18,"13":18.3,"14":22.43,"15":26.35,"16":27.36,"17":27.36,"18":27.36,"19":27.36}},{"date":"2025-01-19","day_of_week":"Sunday","total_solar_kwh":30.19,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"16:33","hourly_soc":{"5":0.02,"6":0.12,"7":0.51,"8":1.41,"9":3.32,"10":6.12,"11":9.24,"12":12.92,"13":16.36,"14":19.94,"15":23.63,"16":25.93,"17":27.27,"18":27.36,"19":27.36}},{"date":"2025-01-20","day_of_week":"Monday","total_solar_kwh":29.12,"max_battery_soc_kwh":27.06,"battery_filled_pct":98.9,"time_to_full":"17:03","hourly_soc":{"5":0.01,"6":0.14,"7":0.68,"8":1.69,"9":3.42,"10":5.72,"11":8.77,"12":12.1,"13":15.57,"14":19.24,"15":22.76,"16":25.09,"17":26.52,"18":27.0,"19":27.05}},{"date":"2025-01-21","day_of_week":"Tuesday","total_solar_kwh":33.51,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:33","hourly_soc":{"5":0.01,"6":0.12,"7":0.38,"8":1.16,"9":3.04,"10":6.01,"11":9.75,"12":13.87,"13":18.0,"14":22.11,"15":25.9,"16":27.36,"17":27.36,"18":27.36,"19":27.36}},{"date":"2025-01-22","day_of_week":"Wednesday","total_solar_kwh":33.56,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:28","hourly_soc":{"5":0.0,"6":0.1,"7":0.38,"8":1.2,"9":3.13,"10":6.21,"11":10.09,"12":14.22,"13":18.35,"14":22.3,"15":26.08,"16":27.36,"17":27.36,"18":27.36,"19":27.36}},{"date":"2025-01-23","day_of_week":"Thursday","total_solar_kwh":21.61,"max_battery_soc_kwh":20.07,"battery_filled_pct":73.4,"time_to_full":null,"hourly_soc":{"5":0.01,"6":0.15,"7":0.64,"8":1.47,"9":3.04,"10":4.74,"11":6.7,"12":8.69,"13":10.31,"14":12.33,"15":15.91,"16":18.44,"17":19.78,"18":20.01,"19":20.07}},{"date":"2025-01-24","day_of_week":"Friday","total_solar_kwh":34.47,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:24","hourly_soc":{"5":0.01,"6":0.14,"7":0.45,"8":1.22,"9":3.13,"10":6.19,"11":10.11,"12":14.23,"13":18.36,"14":22.49,"15":26.39,"16":27.36,"17":27.36,"18":27.36,"19":27.36}},{"date":"2025-01-25","day_of_week":"Saturday","total_solar_kwh":34.23,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:24","hourly_soc":{"5":0.01,"6":0.2,"7":0.74,"8":1.65,"9":3.47,"10":6.45,"11":10.24,"12":14.36,"13":18.49,"14":22.61,"15":26.48,"16":27.36,"17":27.36,"18":27.36,"19":27.36}},{"date":"2025-01-26","day_of_week":"Sunday","total_solar_kwh":28.64,"max_battery_soc_kwh":26.66,"battery_filled_pct":97.5,"time_to_full":"16:59","hourly_soc":{"5":0.0,"6":0.17,"7":0.63,"8":1.53,"9":3.2,"10":6.04,"11":9.73,"12":13.36,"13":16.82,"14":19.5,"15":22.75,"16":25.21,"17":26.4,"18":26.58,"19":26.66}},{"date":"2025-01-27","day_of_week":"Monday","total_solar_kwh":31.52,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"16:14","hourly_soc":{"5":0.01,"6":0.1,"7":0.39,"8":1.2,"9":2.95,"10":5.78,"11":9.42,"12":13.13,"13":16.87,"14":20.88,"15":24.36,"16":26.61,"17":27.36,"18":27.36,"19":27.36}},{"date":"2025-01-28","day_of_week":"Tuesday","total_solar_kwh":32.6,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:54","hourly_soc":{"5":0.01,"6":0.12,"7":0.71,"8":1.83,"9":3.61,"10":5.73,"11":8.8,"12":12.73,"13":16.86,"14":20.98,"15":24.93,"16":27.13,"17":27.36,"18":27.36,"19":27.36}},{"date":"2025-01-29","day_of_week":"Wednesday","total_solar_kwh":33.45,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:29","hourly_soc":{"5":0.0,"6":0.1,"7":0.4,"8":1.12,"9":3.01,"10":6.02,"11":9.86,"12":13.98,"13":18.11,"14":22.24,"15":26.16,"16":27.36,"17":27.36,"18":27.36,"19":27.36}},{"date":"2025-01-30","day_of_week":"Thursday","total_solar_kwh":33.41,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:29","hourly_soc":{"5":0.01,"6":0.13,"7":0.45,"8":1.18,"9":3.02,"10":6.04,"11":9.89,"12":14.02,"13":18.14,"14":22.27,"15":26.18,"16":27.36,"17":27.36,"18":27.36,"19":27.36}},{"date":"2025-01-31","day_of_week":"Friday","total_solar_kwh":32.61,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:34","hourly_soc":{"5":0.0,"6":0.08,"7":0.31,"8":0.97,"9":2.75,"10":5.69,"11":9.46,"12":13.58,"13":17.71,"14":21.83,"15":25.72,"16":27.34,"17":27.36,"18":27.36,"19":27.36}},{"date":"2025-02-01","day_of_week":"Saturday","total_solar_kwh":32.16,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:39","hourly_soc":{"5":0.01,"6":0.1,"7":0.33,"8":0.99,"9":2.73,"10":5.57,"11":9.24,"12":13.34,"13":17.47,"14":21.6,"15":25.48,"16":27.28,"17":27.36,"18":27.36,"19":27.36}},{"date":"2025-02-02","day_of_week":"Sunday","total_solar_kwh":31.12,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:50","hourly_soc":{"5":0.0,"6":0.08,"7":0.38,"8":1.12,"9":2.72,"10":5.38,"11":8.78,"12":12.73,"13":16.85,"14":20.98,"15":24.93,"16":27.08,"17":27.36,"18":27.36,"19":27.36}},{"date":"2025-02-03","day_of_week":"Monday","total_solar_kwh":29.93,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"16:05","hourly_soc":{"5":0.0,"6":0.08,"7":0.32,"8":0.93,"9":2.41,"10":4.95,"11":8.3,"12":12.22,"13":16.35,"14":20.48,"15":24.4,"16":26.68,"17":27.36,"18":27.36,"19":27.36}},{"date":"2025-02-04","day_of_week":"Tuesday","total_solar_kwh":30.72,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"16:15","hourly_soc":{"5":0.0,"6":0.09,"7":0.43,"8":1.08,"9":2.61,"10":4.66,"11":8.02,"12":12.01,"13":16.14,"14":20.27,"15":24.22,"16":26.6,"17":27.36,"18":27.36,"19":27.36}},{"date":"2025-02-05","day_of_week":"Wednesday","total_solar_kwh":31.48,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:50","hourly_soc":{"5":0.0,"6":0.07,"7":0.28,"8":0.83,"9":2.42,"10":5.16,"11":8.77,"12":12.85,"13":16.98,"14":21.11,"15":25.03,"16":27.14,"17":27.36,"18":27.36,"19":27.36}},{"date":"2025-02-06","day_of_week":"Thursday","total_solar_kwh":29.98,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"16:05","hourly_soc":{"5":0.0,"6":0.08,"7":0.39,"8":1.04,"9":2.53,"10":5.06,"11":8.39,"12":12.29,"13":16.41,"14":20.54,"15":24.44,"16":26.72,"17":27.36,"18":27.36,"19":27.36}},{"date":"2025-02-07","day_of_week":"Friday","total_solar_kwh":32.83,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:31","hourly_soc":{"5":0.0,"6":0.1,"7":0.57,"8":1.56,"9":3.17,"10":5.84,"11":9.42,"12":13.5,"13":17.63,"14":21.76,"15":25.68,"16":27.34,"17":27.36,"18":27.36,"19":27.36}},{"date":"2025-02-08","day_of_week":"Saturday","total_solar_kwh":31.98,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:47","hourly_soc":{"5":0.0,"6":0.08,"7":0.29,"8":0.84,"9":2.43,"10":5.2,"11":8.87,"12":12.98,"13":17.1,"14":21.23,"15":25.12,"16":27.16,"17":27.36,"18":27.36,"19":27.36}},{"date":"2025-02-09","day_of_week":"Sunday","total_solar_kwh":31.16,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:57","hourly_soc":{"5":0.0,"6":0.07,"7":0.36,"8":0.94,"9":2.49,"10":5.18,"11":8.74,"12":12.8,"13":16.93,"14":21.06,"15":24.92,"16":27.04,"17":27.36,"18":27.36,"19":27.36}},{"date":"2025-02-10","day_of_week":"Monday","total_solar_kwh":30.43,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"16:02","hourly_soc":{"5":0.0,"6":0.05,"7":0.25,"8":0.79,"9":2.32,"10":4.98,"11":8.52,"12":12.58,"13":16.71,"14":20.83,"15":24.68,"16":26.86,"17":27.36,"18":27.36,"19":27.36}},{"date":"2025-02-11","day_of_week":"Tuesday","total_solar_kwh":29.36,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"16:22","hourly_soc":{"5":0.0,"6":0.08,"7":0.33,"8":0.85,"9":2.31,"10":4.85,"11":8.22,"12":12.12,"13":16.24,"14":20.37,"15":24.19,"16":26.33,"17":27.26,"18":27.36,"19":27.36}},{"date":"2025-02-12","day_of_week":"Wednesday","total_solar_kwh":28.52,"max_battery_soc_kwh":27.1,"battery_filled_pct":99.1,"time_to_full":"16:47","hourly_soc":{"5":0.0,"6":0.06,"7":0.25,"8":0.72,"9":2.12,"10":4.6,"11":7.92,"12":11.81,"13":15.93,"14":20.02,"15":23.78,"16":25.7,"17":26.78,"18":27.07,"19":27.1}},{"date":"2025-02-13","day_of_week":"Thursday","total_solar_kwh":26.3,"max_battery_soc_kwh":23.92,"battery_filled_pct":87.4,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.02,"7":0.17,"8":0.52,"9":1.45,"10":2.91,"11":5.67,"12":9.11,"13":12.71,"14":16.6,"15":20.38,"16":22.71,"17":23.7,"18":23.89,"19":23.92}},{"date":"2025-02-14","day_of_week":"Friday","total_solar_kwh":26.61,"max_battery_soc_kwh":23.91,"battery_filled_pct":87.4,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.02,"7":0.3,"8":1.08,"9":2.62,"10":4.62,"11":7.08,"12":10.46,"13":14.07,"14":17.49,"15":20.14,"16":22.51,"17":23.65,"18":23.87,"19":23.91}},{"date":"2025-02-15","day_of_week":"Saturday","total_solar_kwh":28.69,"max_battery_soc_kwh":25.85,"battery_filled_pct":94.5,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.04,"7":0.37,"8":1.31,"9":2.98,"10":5.08,"11":7.84,"12":11.24,"13":14.3,"14":17.9,"15":21.64,"16":24.16,"17":25.43,"18":25.81,"19":25.85}},{"date":"2025-02-16","day_of_week":"Sunday","total_solar_kwh":31.09,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"16:13","hourly_soc":{"5":0.0,"6":0.08,"7":0.35,"8":1.16,"9":2.66,"10":5.0,"11":8.18,"12":12.3,"13":16.43,"14":20.56,"15":24.36,"16":26.64,"17":27.36,"18":27.36,"19":27.36}},{"date":"2025-02-17","day_of_week":"Monday","total_solar_kwh":29.86,"max_battery_soc_kwh":27.09,"battery_filled_pct":99.0,"time_to_full":"16:28","hourly_soc":{"5":0.0,"6":0.05,"7":0.24,"8":0.74,"9":2.27,"10":5.0,"11":8.29,"12":12.14,"13":16.16,"14":20.18,"15":23.91,"16":26.08,"17":26.89,"18":27.03,"19":27.09}},{"date":"2025-02-18","day_of_week":"Tuesday","total_solar_kwh":30.91,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"16:08","hourly_soc":{"5":0.0,"6":0.05,"7":0.31,"8":0.81,"9":2.29,"10":4.96,"11":8.57,"12":12.66,"13":16.79,"14":20.92,"15":24.67,"16":26.83,"17":27.36,"18":27.36,"19":27.36}},{"date":"2025-02-19","day_of_week":"Wednesday","total_solar_kwh":31.39,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:54","hourly_soc":{"5":0.0,"6":0.05,"7":0.29,"8":0.92,"9":2.55,"10":5.28,"11":8.93,"12":13.03,"13":17.16,"14":21.29,"15":25.04,"16":27.07,"17":27.36,"18":27.36,"19":27.36}},{"date":"2025-02-20","day_of_week":"Thursday","total_solar_kwh":30.28,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"16:09","hourly_soc":{"5":0.0,"6":0.04,"7":0.22,"8":0.69,"9":2.19,"10":4.92,"11":8.56,"12":12.65,"13":16.78,"14":20.91,"15":24.6,"16":26.68,"17":27.36,"18":27.36,"19":27.36}},{"date":"2025-02-21","day_of_week":"Friday","total_solar_kwh":29.71,"max_battery_soc_kwh":27.26,"battery_filled_pct":99.6,"time_to_full":"16:24","hourly_soc":{"5":0.0,"6":0.04,"7":0.23,"8":0.68,"9":2.11,"10":4.7,"11":8.2,"12":12.22,"13":16.35,"14":20.46,"15":24.03,"16":26.19,"17":26.97,"18":27.22,"19":27.25}},{"date":"2025-02-22","day_of_week":"Saturday","total_solar_kwh":22.17,"max_battery_soc_kwh":20.92,"battery_filled_pct":76.5,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.04,"7":0.26,"8":0.71,"9":2.05,"10":4.55,"11":7.95,"12":11.93,"13":15.62,"14":17.62,"15":19.18,"16":20.22,"17":20.73,"18":20.91,"19":20.92}},{"date":"2025-02-23","day_of_week":"Sunday","total_solar_kwh":29.05,"max_battery_soc_kwh":26.21,"battery_filled_pct":95.8,"time_to_full":"17:32","hourly_soc":{"5":0.0,"6":0.05,"7":0.4,"8":1.1,"9":2.48,"10":5.07,"11":8.54,"12":12.22,"13":15.32,"14":19.35,"15":23.07,"16":25.21,"17":25.99,"18":26.18,"19":26.21}},{"date":"2025-02-24","day_of_week":"Monday","total_solar_kwh":28.13,"max_battery_soc_kwh":25.13,"battery_filled_pct":91.9,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.04,"7":0.33,"8":1.1,"9":2.33,"10":4.59,"11":7.24,"12":10.52,"13":14.47,"14":18.6,"15":22.28,"16":24.36,"17":25.04,"18":25.11,"19":25.13}},{"date":"2025-02-25","day_of_week":"Tuesday","total_solar_kwh":28.36,"max_battery_soc_kwh":26.37,"battery_filled_pct":96.4,"time_to_full":"16:42","hourly_soc":{"5":0.0,"6":0.02,"7":0.18,"8":0.58,"9":1.89,"10":4.38,"11":7.77,"12":11.76,"13":15.89,"14":20.01,"15":23.66,"16":25.65,"17":26.29,"18":26.36,"19":26.37}},{"date":"2025-02-26","day_of_week":"Wednesday","total_solar_kwh":28.04,"max_battery_soc_kwh":26.02,"battery_filled_pct":95.1,"time_to_full":"18:07","hourly_soc":{"5":0.0,"6":0.03,"7":0.25,"8":0.68,"9":1.94,"10":4.35,"11":7.69,"12":11.58,"13":15.69,"14":19.82,"15":23.44,"16":25.29,"17":25.93,"18":26.0,"19":26.02}},{"date":"2025-02-27","day_of_week":"Thursday","total_solar_kwh":26.3,"max_battery_soc_kwh":24.86,"battery_filled_pct":90.9,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.04,"7":0.27,"8":0.73,"9":1.96,"10":4.36,"11":7.59,"12":11.44,"13":15.55,"14":19.39,"15":22.38,"16":24.05,"17":24.66,"18":24.85,"19":24.86}},{"date":"2025-02-28","day_of_week":"Friday","total_solar_kwh":27.89,"max_battery_soc_kwh":26.13,"battery_filled_pct":95.5,"time_to_full":"16:58","hourly_soc":{"5":0.0,"6":0.02,"7":0.28,"8":1.04,"9":2.27,"10":4.63,"11":7.91,"12":11.82,"13":15.94,"14":20.07,"15":23.62,"16":25.52,"17":26.06,"18":26.12,"19":26.13}},{"date":"2025-03-01","day_of_week":"Saturday","total_solar_kwh":23.56,"max_battery_soc_kwh":22.19,"battery_filled_pct":81.1,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.03,"7":0.29,"8":1.05,"9":2.32,"10":4.02,"11":7.11,"12":10.59,"13":13.89,"14":17.09,"15":19.59,"16":21.53,"17":22.09,"18":22.17,"19":22.19}},{"date":"2025-03-02","day_of_week":"Sunday","total_solar_kwh":22.61,"max_battery_soc_kwh":20.83,"battery_filled_pct":76.1,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.02,"7":0.33,"8":1.06,"9":2.45,"10":4.35,"11":6.51,"12":8.56,"13":11.23,"14":14.85,"15":18.25,"16":20.18,"17":20.73,"18":20.81,"19":20.83}},{"date":"2025-03-03","day_of_week":"Monday","total_solar_kwh":27.78,"max_battery_soc_kwh":25.58,"battery_filled_pct":93.5,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.02,"7":0.18,"8":0.54,"9":1.79,"10":4.21,"11":7.56,"12":11.53,"13":15.66,"14":19.78,"15":23.28,"16":25.04,"17":25.54,"18":25.57,"19":25.58}},{"date":"2025-03-04","day_of_week":"Tuesday","total_solar_kwh":26.94,"max_battery_soc_kwh":25.27,"battery_filled_pct":92.4,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.02,"7":0.17,"8":0.53,"9":1.74,"10":4.12,"11":7.38,"12":11.25,"13":15.37,"14":19.5,"15":22.95,"16":24.77,"17":25.21,"18":25.26,"19":25.27}},{"date":"2025-03-05","day_of_week":"Wednesday","total_solar_kwh":26.77,"max_battery_soc_kwh":25.06,"battery_filled_pct":91.6,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.02,"7":0.17,"8":0.52,"9":1.7,"10":4.03,"11":7.24,"12":11.11,"13":15.23,"14":19.36,"15":22.77,"16":24.55,"17":25.0,"18":25.05,"19":25.06}},{"date":"2025-03-06","day_of_week":"Thursday","total_solar_kwh":26.77,"max_battery_soc_kwh":25.11,"battery_filled_pct":91.8,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.03,"7":0.23,"8":0.69,"9":1.91,"10":4.24,"11":7.18,"12":11.12,"13":15.24,"14":19.37,"15":22.77,"16":24.54,"17":25.01,"18":25.1,"19":25.11}},{"date":"2025-03-07","day_of_week":"Friday","total_solar_kwh":25.0,"max_battery_soc_kwh":23.87,"battery_filled_pct":87.3,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.02,"7":0.17,"8":0.53,"9":1.65,"10":3.84,"11":6.94,"12":10.65,"13":14.7,"14":18.59,"15":21.6,"16":23.26,"17":23.77,"18":23.86,"19":23.87}},{"date":"2025-03-08","day_of_week":"Saturday","total_solar_kwh":22.78,"max_battery_soc_kwh":21.69,"battery_filled_pct":79.3,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.02,"7":0.15,"8":0.48,"9":1.59,"10":3.85,"11":7.0,"12":10.5,"13":14.44,"14":17.3,"15":19.46,"16":21.22,"17":21.63,"18":21.69,"19":21.69}},{"date":"2025-03-09","day_of_week":"Sunday","total_solar_kwh":20.86,"max_battery_soc_kwh":20.0,"battery_filled_pct":73.1,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.01,"7":0.19,"8":0.63,"9":1.56,"10":2.61,"11":4.01,"12":6.8,"13":10.81,"14":14.92,"15":18.1,"16":19.65,"17":19.95,"18":19.99,"19":20.0}},{"date":"2025-03-10","day_of_week":"Monday","total_solar_kwh":23.86,"max_battery_soc_kwh":22.89,"battery_filled_pct":83.6,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.01,"7":0.15,"8":0.46,"9":1.47,"10":3.34,"11":6.27,"12":9.8,"13":13.59,"14":17.68,"15":20.83,"16":22.4,"17":22.8,"18":22.88,"19":22.89}},{"date":"2025-03-11","day_of_week":"Tuesday","total_solar_kwh":14.61,"max_battery_soc_kwh":14.02,"battery_filled_pct":51.3,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.01,"7":0.2,"8":0.81,"9":2.03,"10":3.44,"11":4.85,"12":6.18,"13":8.27,"14":10.71,"15":12.82,"16":13.4,"17":13.84,"18":14.01,"19":14.02}},{"date":"2025-03-12","day_of_week":"Wednesday","total_solar_kwh":24.94,"max_battery_soc_kwh":23.89,"battery_filled_pct":87.3,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.02,"7":0.33,"8":0.89,"9":1.94,"10":4.01,"11":6.99,"12":10.65,"13":14.7,"14":18.82,"15":21.98,"16":23.53,"17":23.84,"18":23.88,"19":23.89}},{"date":"2025-03-13","day_of_week":"Thursday","total_solar_kwh":25.29,"max_battery_soc_kwh":23.97,"battery_filled_pct":87.6,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.01,"7":0.16,"8":0.52,"9":1.59,"10":3.81,"11":6.94,"12":10.71,"13":14.81,"14":18.94,"15":22.12,"16":23.68,"17":23.93,"18":23.96,"19":23.97}},{"date":"2025-03-14","day_of_week":"Friday","total_solar_kwh":24.19,"max_battery_soc_kwh":23.2,"battery_filled_pct":84.8,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.01,"7":0.15,"8":0.47,"9":1.5,"10":3.59,"11":6.56,"12":10.15,"13":14.17,"14":18.27,"15":21.29,"16":22.74,"17":23.12,"18":23.19}},{"date":"2025-03-15","day_of_week":"Saturday","total_solar_kwh":22.54,"max_battery_soc_kwh":21.57,"battery_filled_pct":78.8,"time_to_full":null,"hourly_soc":{"6":0.01,"7":0.14,"8":0.49,"9":1.44,"10":3.44,"11":6.45,"12":9.82,"13":13.16,"14":16.72,"15":19.6,"16":21.14,"17":21.5,"18":21.56}},{"date":"2025-03-16","day_of_week":"Sunday","total_solar_kwh":19.97,"max_battery_soc_kwh":18.69,"battery_filled_pct":68.3,"time_to_full":null,"hourly_soc":{"6":0.01,"7":0.15,"8":0.75,"9":1.71,"10":3.51,"11":6.59,"12":9.68,"13":11.31,"14":14.24,"15":16.96,"16":18.28,"17":18.58,"18":18.68}},{"date":"2025-03-17","day_of_week":"Monday","total_solar_kwh":25.84,"max_battery_soc_kwh":24.12,"battery_filled_pct":88.1,"time_to_full":null,"hourly_soc":{"6":0.01,"7":0.22,"8":0.7,"9":1.93,"10":4.12,"11":7.36,"12":11.04,"13":15.12,"14":19.25,"15":22.29,"16":23.78,"17":24.06,"18":24.11}},{"date":"2025-03-18","day_of_week":"Tuesday","total_solar_kwh":24.85,"max_battery_soc_kwh":23.56,"battery_filled_pct":86.1,"time_to_full":null,"hourly_soc":{"6":0.01,"7":0.15,"8":0.5,"9":1.53,"10":3.74,"11":6.87,"12":10.62,"13":14.71,"14":18.84,"15":21.82,"16":23.27,"17":23.51,"18":23.56}},{"date":"2025-03-19","day_of_week":"Wednesday","total_solar_kwh":24.13,"max_battery_soc_kwh":23.11,"battery_filled_pct":84.5,"time_to_full":null,"hourly_soc":{"6":0.01,"7":0.13,"8":0.43,"9":1.45,"10":3.64,"11":6.77,"12":10.55,"13":14.65,"14":18.74,"15":21.57,"16":22.9,"17":23.07,"18":23.1}},{"date":"2025-03-20","day_of_week":"Thursday","total_solar_kwh":13.76,"max_battery_soc_kwh":13.14,"battery_filled_pct":48.0,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.08,"8":0.24,"9":0.4,"10":0.93,"11":2.63,"12":5.03,"13":7.34,"14":10.09,"15":11.72,"16":12.51,"17":13.0,"18":13.14}},{"date":"2025-03-21","day_of_week":"Friday","total_solar_kwh":24.12,"max_battery_soc_kwh":22.74,"battery_filled_pct":83.1,"time_to_full":null,"hourly_soc":{"6":0.01,"7":0.25,"8":0.79,"9":1.8,"10":3.84,"11":6.47,"12":9.68,"13":13.78,"14":17.91,"15":20.97,"16":22.46,"17":22.69,"18":22.73}},{"date":"2025-03-22","day_of_week":"Saturday","total_solar_kwh":22.33,"max_battery_soc_kwh":21.26,"battery_filled_pct":77.7,"time_to_full":null,"hourly_soc":{"6":0.01,"7":0.15,"8":0.54,"9":1.47,"10":3.4,"11":6.2,"12":9.54,"13":13.38,"14":17.08,"15":19.44,"16":20.76,"17":21.16,"18":21.26}},{"date":"2025-03-23","day_of_week":"Sunday","total_solar_kwh":24.31,"max_battery_soc_kwh":23.18,"battery_filled_pct":84.7,"time_to_full":null,"hourly_soc":{"6":0.01,"7":0.1,"8":0.37,"9":1.28,"10":3.32,"11":6.33,"12":10.0,"13":14.05,"14":18.18,"15":21.14,"16":22.64,"17":23.09,"18":23.17}},{"date":"2025-03-24","day_of_week":"Monday","total_solar_kwh":23.5,"max_battery_soc_kwh":22.49,"battery_filled_pct":82.2,"time_to_full":null,"hourly_soc":{"6":0.01,"7":0.1,"8":0.36,"9":1.25,"10":3.29,"11":6.26,"12":9.92,"13":13.98,"14":18.1,"15":20.97,"16":22.31,"17":22.45,"18":22.49}},{"date":"2025-03-25","day_of_week":"Tuesday","total_solar_kwh":23.44,"max_battery_soc_kwh":22.46,"battery_filled_pct":82.1,"time_to_full":null,"hourly_soc":{"6":0.01,"7":0.14,"8":0.46,"9":1.36,"10":3.38,"11":6.36,"12":10.03,"13":14.08,"14":18.19,"15":20.98,"16":22.28,"17":22.43,"18":22.46}},{"date":"2025-03-26","day_of_week":"Wednesday","total_solar_kwh":22.01,"max_battery_soc_kwh":21.13,"battery_filled_pct":77.2,"time_to_full":null,"hourly_soc":{"6":0.01,"7":0.1,"8":0.36,"9":1.21,"10":3.14,"11":5.97,"12":9.4,"13":13.21,"14":17.09,"15":19.73,"16":20.96,"17":21.1,"18":21.13}},{"date":"2025-03-27","day_of_week":"Thursday","total_solar_kwh":22.17,"max_battery_soc_kwh":21.28,"battery_filled_pct":77.8,"time_to_full":null,"hourly_soc":{"6":0.01,"7":0.09,"8":0.35,"9":1.18,"10":3.11,"11":6.0,"12":9.48,"13":13.32,"14":17.22,"15":19.83,"16":21.05,"17":21.24,"18":21.28}},{"date":"2025-03-28","day_of_week":"Friday","total_solar_kwh":20.97,"max_battery_soc_kwh":20.08,"battery_filled_pct":73.4,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.09,"8":0.61,"9":1.6,"10":3.46,"11":6.21,"12":9.32,"13":12.1,"14":15.77,"15":18.35,"16":19.67,"17":20.05,"18":20.08}},{"date":"2025-03-29","day_of_week":"Saturday","total_solar_kwh":21.87,"max_battery_soc_kwh":21.0,"battery_filled_pct":76.7,"time_to_full":null,"hourly_soc":{"6":0.01,"7":0.09,"8":0.35,"9":1.17,"10":3.04,"11":5.83,"12":9.27,"13":13.06,"14":16.9,"15":19.45,"16":20.67,"17":20.93,"18":20.99}},{"date":"2025-03-30","day_of_week":"Sunday","total_solar_kwh":22.84,"max_battery_soc_kwh":21.93,"battery_filled_pct":80.1,"time_to_full":null,"hourly_soc":{"6":0.01,"7":0.17,"8":0.55,"9":1.43,"10":3.39,"11":6.33,"12":9.92,"13":13.89,"14":17.93,"15":20.57,"16":21.74,"17":21.9,"18":21.93}},{"date":"2025-03-31","day_of_week":"Monday","total_solar_kwh":18.07,"max_battery_soc_kwh":16.85,"battery_filled_pct":61.6,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.06,"8":0.43,"9":1.31,"10":2.93,"11":5.17,"12":7.9,"13":10.72,"14":13.7,"15":15.51,"16":16.62,"17":16.81,"18":16.84}},{"date":"2025-04-01","day_of_week":"Tuesday","total_solar_kwh":21.9,"max_battery_soc_kwh":21.03,"battery_filled_pct":76.9,"time_to_full":null,"hourly_soc":{"6":0.01,"7":0.13,"8":0.49,"9":1.32,"10":3.2,"11":6.05,"12":9.56,"13":13.43,"14":17.34,"15":19.82,"16":20.89,"17":21.0,"18":21.03}},{"date":"2025-04-02","day_of_week":"Wednesday","total_solar_kwh":20.89,"max_battery_soc_kwh":20.05,"battery_filled_pct":73.3,"time_to_full":null,"hourly_soc":{"6":0.01,"7":0.15,"8":0.42,"9":1.18,"10":3.0,"11":5.6,"12":8.61,"13":12.5,"14":16.39,"15":18.84,"16":19.92,"17":20.03,"18":20.05}},{"date":"2025-04-03","day_of_week":"Thursday","total_solar_kwh":17.74,"max_battery_soc_kwh":16.67,"battery_filled_pct":60.9,"time_to_full":null,"hourly_soc":{"6":0.01,"7":0.16,"8":0.78,"9":1.77,"10":3.39,"11":5.13,"12":7.67,"13":11.22,"14":13.84,"15":15.63,"16":16.5,"17":16.65,"18":16.67}},{"date":"2025-04-04","day_of_week":"Friday","total_solar_kwh":14.83,"max_battery_soc_kwh":14.23,"battery_filled_pct":52.0,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.14,"8":0.63,"9":1.67,"10":3.01,"11":4.64,"12":6.86,"13":8.83,"14":10.79,"15":12.94,"16":13.97,"17":14.21,"18":14.23}},{"date":"2025-04-05","day_of_week":"Saturday","total_solar_kwh":18.42,"max_battery_soc_kwh":17.51,"battery_filled_pct":64.0,"time_to_full":null,"hourly_soc":{"6":0.01,"7":0.13,"8":0.38,"9":1.17,"10":2.91,"11":4.33,"12":6.62,"13":10.11,"14":14.13,"15":16.49,"16":17.41,"17":17.49,"18":17.51}},{"date":"2025-04-06","day_of_week":"Sunday","total_solar_kwh":22.26,"max_battery_soc_kwh":21.34,"battery_filled_pct":78.0,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.09,"8":0.45,"9":1.27,"10":3.22,"11":6.15,"12":9.63,"13":13.49,"14":17.28,"15":19.65,"16":20.92,"17":21.29,"18":21.34}},{"date":"2025-04-07","day_of_week":"Monday","total_solar_kwh":16.4,"max_battery_soc_kwh":15.47,"battery_filled_pct":56.5,"time_to_full":null,"hourly_soc":{"6":0.01,"7":0.17,"8":0.64,"9":1.41,"10":2.43,"11":3.5,"12":5.65,"13":8.43,"14":12.12,"15":14.45,"16":15.34,"17":15.45,"18":15.46}},{"date":"2025-04-08","day_of_week":"Tuesday","total_solar_kwh":21.57,"max_battery_soc_kwh":20.71,"battery_filled_pct":75.7,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.12,"8":0.69,"9":1.8,"10":3.6,"11":6.36,"12":9.79,"13":13.61,"14":17.42,"15":19.66,"16":20.49,"17":20.69,"18":20.71}},{"date":"2025-04-09","day_of_week":"Wednesday","total_solar_kwh":7.59,"max_battery_soc_kwh":7.29,"battery_filled_pct":26.6,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.04,"8":0.3,"9":0.71,"10":1.31,"11":2.09,"12":3.13,"13":4.12,"14":5.0,"15":6.5,"16":7.21,"17":7.27,"18":7.29}},{"date":"2025-04-10","day_of_week":"Thursday","total_solar_kwh":20.43,"max_battery_soc_kwh":19.61,"battery_filled_pct":71.7,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.08,"8":0.51,"9":1.31,"10":3.11,"11":5.85,"12":9.12,"13":12.79,"14":16.45,"15":18.64,"16":19.47,"17":19.6,"18":19.61}},{"date":"2025-04-11","day_of_week":"Friday","total_solar_kwh":19.2,"max_battery_soc_kwh":18.43,"battery_filled_pct":67.4,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.08,"8":0.3,"9":0.96,"10":2.64,"11":5.26,"12":8.49,"13":12.1,"14":15.62,"15":17.66,"16":18.35,"17":18.42,"18":18.43}},{"date":"2025-04-12","day_of_week":"Saturday","total_solar_kwh":18.8,"max_battery_soc_kwh":18.04,"battery_filled_pct":65.9,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.07,"8":0.27,"9":0.95,"10":2.64,"11":5.2,"12":8.33,"13":11.85,"14":15.29,"15":17.29,"16":17.96,"17":18.03,"18":18.04}},{"date":"2025-04-13","day_of_week":"Sunday","total_solar_kwh":18.54,"max_battery_soc_kwh":17.8,"battery_filled_pct":65.1,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.07,"8":0.27,"9":0.89,"10":2.52,"11":5.07,"12":8.21,"13":11.7,"14":15.11,"15":17.04,"16":17.68,"17":17.78,"18":17.8}},{"date":"2025-04-14","day_of_week":"Monday","total_solar_kwh":17.93,"max_battery_soc_kwh":17.21,"battery_filled_pct":62.9,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.06,"8":0.26,"9":0.89,"10":2.49,"11":4.95,"12":7.91,"13":11.31,"14":14.62,"15":16.48,"16":17.1,"17":17.2,"18":17.21}},{"date":"2025-04-15","day_of_week":"Tuesday","total_solar_kwh":14.28,"max_battery_soc_kwh":13.71,"battery_filled_pct":50.1,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.07,"8":0.4,"9":1.22,"10":2.47,"11":4.05,"12":6.6,"13":8.98,"14":11.29,"15":12.89,"16":13.58,"17":13.69,"18":13.71}},{"date":"2025-04-16","day_of_week":"Wednesday","total_solar_kwh":17.79,"max_battery_soc_kwh":17.08,"battery_filled_pct":62.4,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.08,"8":0.29,"9":0.9,"10":2.43,"11":4.77,"12":8.04,"13":11.42,"14":14.71,"15":16.52,"16":17.02,"17":17.07,"18":17.08}},{"date":"2025-04-17","day_of_week":"Thursday","total_solar_kwh":16.98,"max_battery_soc_kwh":16.29,"battery_filled_pct":59.5,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.09,"8":0.5,"9":1.19,"10":2.91,"11":5.29,"12":8.0,"13":10.94,"14":13.56,"15":15.24,"16":16.01,"17":16.27,"18":16.29}},{"date":"2025-04-18","day_of_week":"Friday","total_solar_kwh":14.61,"max_battery_soc_kwh":14.02,"battery_filled_pct":51.3,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.09,"8":0.38,"9":1.15,"10":2.42,"11":4.36,"12":6.6,"13":8.59,"14":11.55,"15":13.3,"16":13.89,"17":14.01,"18":14.02}},{"date":"2025-04-19","day_of_week":"Saturday","total_solar_kwh":7.81,"max_battery_soc_kwh":7.49,"battery_filled_pct":27.4,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.04,"8":0.36,"9":0.99,"10":1.99,"11":2.77,"12":3.62,"13":4.81,"14":5.9,"15":6.69,"16":7.23,"17":7.48,"18":7.49}},{"date":"2025-04-20","day_of_week":"Sunday","total_solar_kwh":14.51,"max_battery_soc_kwh":13.87,"battery_filled_pct":50.7,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.11,"8":0.58,"9":1.56,"10":3.01,"11":5.27,"12":7.77,"13":9.78,"14":11.71,"15":13.18,"16":13.72,"17":13.86,"18":13.87}},{"date":"2025-04-21","day_of_week":"Monday","total_solar_kwh":10.71,"max_battery_soc_kwh":10.27,"battery_filled_pct":37.5,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.05,"8":0.48,"9":1.38,"10":2.67,"11":3.91,"12":5.39,"13":7.01,"14":8.71,"15":9.65,"16":10.14,"17":10.27,"18":10.27}},{"date":"2025-04-22","day_of_week":"Tuesday","total_solar_kwh":17.74,"max_battery_soc_kwh":17.03,"battery_filled_pct":62.3,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.09,"8":0.6,"9":1.59,"10":3.11,"11":4.83,"12":7.51,"13":11.08,"14":14.54,"15":16.44,"16":16.97,"17":17.02,"18":17.03}},{"date":"2025-04-23","day_of_week":"Wednesday","total_solar_kwh":17.62,"max_battery_soc_kwh":16.92,"battery_filled_pct":61.8,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.04,"8":0.23,"9":0.77,"10":2.26,"11":4.67,"12":7.7,"13":11.1,"14":14.43,"15":16.26,"16":16.82,"17":16.91,"18":16.92}},{"date":"2025-04-24","day_of_week":"Thursday","total_solar_kwh":17.55,"max_battery_soc_kwh":16.85,"battery_filled_pct":61.6,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.05,"8":0.22,"9":0.72,"10":2.18,"11":4.58,"12":7.61,"13":10.97,"14":14.11,"15":15.76,"16":16.57,"17":16.84,"18":16.85}},{"date":"2025-04-25","day_of_week":"Friday","total_solar_kwh":5.98,"max_battery_soc_kwh":5.74,"battery_filled_pct":21.0,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.02,"8":0.21,"9":0.84,"10":1.37,"11":2.0,"12":3.11,"13":4.14,"14":4.82,"15":5.39,"16":5.66,"17":5.73,"18":5.74}},{"date":"2025-04-26","day_of_week":"Saturday","total_solar_kwh":16.1,"max_battery_soc_kwh":15.46,"battery_filled_pct":56.5,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.04,"8":0.2,"9":0.63,"10":2.04,"11":4.1,"12":6.61,"13":10.08,"14":13.17,"15":14.9,"16":15.39,"17":15.45,"18":15.46}},{"date":"2025-04-27","day_of_week":"Sunday","total_solar_kwh":12.37,"max_battery_soc_kwh":11.72,"battery_filled_pct":42.8,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.03,"8":0.19,"9":0.71,"10":1.79,"11":3.36,"12":5.16,"13":6.92,"14":9.25,"15":10.81,"16":11.5,"17":11.71,"18":11.72}},{"date":"2025-04-28","day_of_week":"Monday","total_solar_kwh":16.23,"max_battery_soc_kwh":15.58,"battery_filled_pct":56.9,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.1,"8":0.66,"9":1.45,"10":2.56,"11":4.61,"12":6.8,"13":10.3,"14":13.46,"15":14.83,"16":15.5,"17":15.57,"18":15.58}},{"date":"2025-04-29","day_of_week":"Tuesday","total_solar_kwh":15.33,"max_battery_soc_kwh":14.67,"battery_filled_pct":53.6,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.03,"8":0.19,"9":0.72,"10":2.1,"11":4.35,"12":7.09,"13":9.21,"14":11.85,"15":13.81,"16":14.54,"17":14.66,"18":14.67}},{"date":"2025-04-30","day_of_week":"Wednesday","total_solar_kwh":16.56,"max_battery_soc_kwh":15.89,"battery_filled_pct":58.1,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.04,"8":0.22,"9":0.7,"10":2.05,"11":4.3,"12":7.31,"13":10.67,"14":13.82,"15":15.46,"16":15.84,"17":15.89,"18":15.89}},{"date":"2025-05-01","day_of_week":"Thursday","total_solar_kwh":16.31,"max_battery_soc_kwh":15.66,"battery_filled_pct":57.2,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.03,"8":0.2,"9":0.67,"10":2.04,"11":4.42,"12":7.41,"13":10.67,"14":13.7,"15":15.26,"16":15.61,"17":15.65,"18":15.66}},{"date":"2025-05-02","day_of_week":"Friday","total_solar_kwh":16.02,"max_battery_soc_kwh":15.38,"battery_filled_pct":56.2,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.04,"8":0.21,"9":0.65,"10":2.0,"11":4.31,"12":7.2,"13":10.43,"14":13.45,"15":15.0,"16":15.33,"17":15.37}},{"date":"2025-05-03","day_of_week":"Saturday","total_solar_kwh":16.57,"max_battery_soc_kwh":15.9,"battery_filled_pct":58.1,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.07,"8":0.4,"9":1.06,"10":2.39,"11":4.73,"12":7.54,"13":10.73,"14":13.67,"15":15.11,"16":15.73,"17":15.9}},{"date":"2025-05-04","day_of_week":"Sunday","total_solar_kwh":14.8,"max_battery_soc_kwh":14.21,"battery_filled_pct":51.9,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.06,"8":0.46,"9":1.39,"10":2.87,"11":4.65,"12":6.68,"13":9.46,"14":12.14,"15":13.66,"16":14.12,"17":14.21}},{"date":"2025-05-05","day_of_week":"Monday","total_solar_kwh":14.94,"max_battery_soc_kwh":14.34,"battery_filled_pct":52.4,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.03,"8":0.17,"9":0.58,"10":1.81,"11":3.94,"12":6.68,"13":9.78,"14":12.59,"15":14.0,"16":14.29,"17":14.33}},{"date":"2025-05-06","day_of_week":"Tuesday","total_solar_kwh":14.88,"max_battery_soc_kwh":14.28,"battery_filled_pct":52.2,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.04,"8":0.2,"9":0.66,"10":1.76,"11":3.79,"12":6.52,"13":9.58,"14":12.38,"15":13.64,"16":14.15,"17":14.28}},{"date":"2025-05-07","day_of_week":"Wednesday","total_solar_kwh":14.91,"max_battery_soc_kwh":14.32,"battery_filled_pct":52.3,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.04,"8":0.35,"9":0.99,"10":1.95,"11":3.79,"12":6.33,"13":9.45,"14":12.32,"15":13.83,"16":14.25,"17":14.31}},{"date":"2025-05-08","day_of_week":"Thursday","total_solar_kwh":12.76,"max_battery_soc_kwh":12.24,"battery_filled_pct":44.8,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.05,"8":0.45,"9":1.36,"10":2.46,"11":3.41,"12":4.86,"13":7.66,"14":10.46,"15":11.86,"16":12.19,"17":12.24}},{"date":"2025-05-09","day_of_week":"Friday","total_solar_kwh":14.79,"max_battery_soc_kwh":14.2,"battery_filled_pct":51.9,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.03,"8":0.19,"9":0.6,"10":1.84,"11":3.99,"12":6.72,"13":9.77,"14":12.53,"15":13.89,"16":14.16,"17":14.2}},{"date":"2025-05-10","day_of_week":"Saturday","total_solar_kwh":14.66,"max_battery_soc_kwh":14.08,"battery_filled_pct":51.5,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.04,"8":0.2,"9":0.6,"10":1.83,"11":3.97,"12":6.71,"13":9.75,"14":12.47,"15":13.81,"16":14.04,"17":14.07}},{"date":"2025-05-11","day_of_week":"Sunday","total_solar_kwh":14.32,"max_battery_soc_kwh":13.75,"battery_filled_pct":50.3,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.04,"8":0.2,"9":0.59,"10":1.78,"11":3.86,"12":6.52,"13":9.5,"14":12.19,"15":13.5,"16":13.71,"17":13.75}},{"date":"2025-05-12","day_of_week":"Monday","total_solar_kwh":14.0,"max_battery_soc_kwh":13.44,"battery_filled_pct":49.1,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.02,"8":0.17,"9":0.55,"10":1.71,"11":3.74,"12":6.33,"13":9.3,"14":11.94,"15":13.2,"16":13.4,"17":13.43}},{"date":"2025-05-13","day_of_week":"Tuesday","total_solar_kwh":13.82,"max_battery_soc_kwh":13.27,"battery_filled_pct":48.5,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.03,"8":0.19,"9":0.56,"10":1.7,"11":3.72,"12":6.3,"13":9.23,"14":11.82,"15":13.04,"16":13.23,"17":13.26}},{"date":"2025-05-14","day_of_week":"Wednesday","total_solar_kwh":11.93,"max_battery_soc_kwh":11.45,"battery_filled_pct":41.9,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.02,"8":0.17,"9":0.53,"10":1.65,"11":3.46,"12":5.57,"13":8.11,"14":10.17,"15":11.08,"16":11.36,"17":11.45}},{"date":"2025-05-15","day_of_week":"Thursday","total_solar_kwh":8.11,"max_battery_soc_kwh":7.78,"battery_filled_pct":28.4,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.02,"8":0.18,"9":0.75,"10":1.59,"11":2.54,"12":3.9,"13":5.3,"14":6.59,"15":7.36,"16":7.72,"17":7.78}},{"date":"2025-05-16","day_of_week":"Friday","total_solar_kwh":8.61,"max_battery_soc_kwh":8.27,"battery_filled_pct":30.2,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.02,"8":0.27,"9":0.95,"10":1.97,"11":3.11,"12":4.55,"13":6.15,"14":6.95,"15":7.85,"16":8.19,"17":8.26}},{"date":"2025-05-17","day_of_week":"Saturday","total_solar_kwh":8.91,"max_battery_soc_kwh":8.55,"battery_filled_pct":31.3,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.02,"8":0.2,"9":0.65,"10":1.48,"11":2.89,"12":4.45,"13":6.06,"14":7.38,"15":8.01,"16":8.47,"17":8.55}},{"date":"2025-05-18","day_of_week":"Sunday","total_solar_kwh":13.32,"max_battery_soc_kwh":12.78,"battery_filled_pct":46.7,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.02,"8":0.16,"9":0.52,"10":1.65,"11":3.7,"12":6.38,"13":9.33,"14":11.34,"15":12.45,"16":12.75,"17":12.78}},{"date":"2025-05-19","day_of_week":"Monday","total_solar_kwh":13.67,"max_battery_soc_kwh":13.12,"battery_filled_pct":48.0,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.02,"8":0.15,"9":0.49,"10":1.6,"11":3.61,"12":6.24,"13":9.22,"14":11.78,"15":12.95,"16":13.1,"17":13.12}},{"date":"2025-05-20","day_of_week":"Tuesday","total_solar_kwh":13.41,"max_battery_soc_kwh":12.88,"battery_filled_pct":47.1,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.02,"8":0.17,"9":0.51,"10":1.59,"11":3.55,"12":6.11,"13":9.04,"14":11.56,"15":12.7,"16":12.85,"17":12.87}},{"date":"2025-05-21","day_of_week":"Wednesday","total_solar_kwh":9.68,"max_battery_soc_kwh":9.29,"battery_filled_pct":33.9,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.03,"8":0.27,"9":0.78,"10":1.85,"11":3.2,"12":4.5,"13":6.73,"14":8.15,"15":8.92,"16":9.25,"17":9.29}},{"date":"2025-05-22","day_of_week":"Thursday","total_solar_kwh":12.98,"max_battery_soc_kwh":12.46,"battery_filled_pct":45.6,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.02,"8":0.14,"9":0.48,"10":1.52,"11":3.45,"12":5.97,"13":8.81,"14":11.22,"15":12.29,"16":12.44,"17":12.46}},{"date":"2025-05-23","day_of_week":"Friday","total_solar_kwh":12.77,"max_battery_soc_kwh":12.26,"battery_filled_pct":44.8,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.02,"8":0.14,"9":0.46,"10":1.49,"11":3.38,"12":5.82,"13":8.61,"14":10.99,"15":12.05,"16":12.23,"17":12.26}},{"date":"2025-05-24","day_of_week":"Saturday","total_solar_kwh":13.33,"max_battery_soc_kwh":12.79,"battery_filled_pct":46.8,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.02,"8":0.18,"9":0.7,"10":1.81,"11":3.54,"12":6.01,"13":8.72,"14":11.1,"15":12.26,"16":12.69,"17":12.79}},{"date":"2025-05-25","day_of_week":"Sunday","total_solar_kwh":12.83,"max_battery_soc_kwh":12.31,"battery_filled_pct":45.0,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.03,"8":0.23,"9":0.58,"10":1.48,"11":3.28,"12":5.71,"13":8.48,"14":10.96,"15":12.1,"16":12.28,"17":12.31}},{"date":"2025-05-26","day_of_week":"Monday","total_solar_kwh":7.64,"max_battery_soc_kwh":7.34,"battery_filled_pct":26.8,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.02,"8":0.24,"9":0.9,"10":1.83,"11":2.25,"12":2.77,"13":4.22,"14":5.83,"15":6.93,"16":7.28,"17":7.33}},{"date":"2025-05-27","day_of_week":"Tuesday","total_solar_kwh":11.41,"max_battery_soc_kwh":10.95,"battery_filled_pct":40.0,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.01,"8":0.19,"9":0.65,"10":1.49,"11":3.17,"12":5.2,"13":7.53,"14":9.49,"15":10.55,"16":10.85,"17":10.95}},{"date":"2025-05-28","day_of_week":"Wednesday","total_solar_kwh":10.82,"max_battery_soc_kwh":10.39,"battery_filled_pct":38.0,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.01,"8":0.2,"9":0.76,"10":1.81,"11":3.38,"12":5.1,"13":7.07,"14":8.88,"15":9.95,"16":10.33,"17":10.38}},{"date":"2025-05-29","day_of_week":"Thursday","total_solar_kwh":12.42,"max_battery_soc_kwh":11.92,"battery_filled_pct":43.6,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.01,"8":0.11,"9":0.49,"10":1.35,"11":3.06,"12":5.44,"13":8.18,"14":10.59,"15":11.71,"16":11.9,"17":11.92}},{"date":"2025-05-30","day_of_week":"Friday","total_solar_kwh":12.23,"max_battery_soc_kwh":11.74,"battery_filled_pct":42.9,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.01,"8":0.12,"9":0.4,"10":1.31,"11":3.07,"12":5.4,"13":8.1,"14":10.47,"15":11.55,"16":11.72,"17":11.74}},{"date":"2025-05-31","day_of_week":"Saturday","total_solar_kwh":12.41,"max_battery_soc_kwh":11.92,"battery_filled_pct":43.6,"time_to_full":null,"hourly_soc":{"7":0.01,"8":0.16,"9":0.49,"10":1.41,"11":3.19,"12":5.56,"13":8.28,"14":10.67,"15":11.74,"16":11.89,"17":11.91}},{"date":"2025-06-01","day_of_week":"Sunday","total_solar_kwh":10.69,"max_battery_soc_kwh":10.26,"battery_filled_pct":37.5,"time_to_full":null,"hourly_soc":{"7":0.01,"8":0.22,"9":0.81,"10":1.77,"11":3.05,"12":4.58,"13":6.93,"14":8.8,"15":9.73,"16":10.19,"17":10.26}},{"date":"2025-06-02","day_of_week":"Monday","total_solar_kwh":10.54,"max_battery_soc_kwh":10.12,"battery_filled_pct":37.0,"time_to_full":null,"hourly_soc":{"7":0.01,"8":0.08,"9":0.39,"10":1.05,"11":2.7,"12":4.82,"13":6.8,"14":8.94,"15":9.96,"16":10.09,"17":10.12}},{"date":"2025-06-03","day_of_week":"Tuesday","total_solar_kwh":10.61,"max_battery_soc_kwh":10.18,"battery_filled_pct":37.2,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.01,"8":0.18,"9":0.6,"10":1.61,"11":3.0,"12":4.88,"13":7.23,"14":8.83,"15":9.84,"16":10.15,"17":10.18}},{"date":"2025-06-04","day_of_week":"Wednesday","total_solar_kwh":12.31,"max_battery_soc_kwh":11.82,"battery_filled_pct":43.2,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.01,"8":0.11,"9":0.38,"10":1.25,"11":3.03,"12":5.46,"13":8.2,"14":10.6,"15":11.66,"16":11.79,"17":11.82}},{"date":"2025-06-05","day_of_week":"Thursday","total_solar_kwh":6.38,"max_battery_soc_kwh":6.12,"battery_filled_pct":22.4,"time_to_full":null,"hourly_soc":{"7":0.01,"8":0.2,"9":0.89,"10":1.89,"11":3.12,"12":4.31,"13":5.07,"14":5.46,"15":5.91,"16":6.1,"17":6.12}},{"date":"2025-06-06","day_of_week":"Friday","total_solar_kwh":8.75,"max_battery_soc_kwh":8.4,"battery_filled_pct":30.7,"time_to_full":null,"hourly_soc":{"7":0.0,"8":0.05,"9":0.29,"10":0.67,"11":1.46,"12":2.66,"13":4.48,"14":6.75,"15":7.86,"16":8.3,"17":8.4}},{"date":"2025-06-07","day_of_week":"Saturday","total_solar_kwh":4.59,"max_battery_soc_kwh":4.41,"battery_filled_pct":16.1,"time_to_full":null,"hourly_soc":{"7":0.0,"8":0.12,"9":0.32,"10":0.61,"11":1.18,"12":1.52,"13":2.32,"14":3.1,"15":4.01,"16":4.36,"17":4.41}},{"date":"2025-06-08","day_of_week":"Sunday","total_solar_kwh":10.56,"max_battery_soc_kwh":10.14,"battery_filled_pct":37.1,"time_to_full":null,"hourly_soc":{"7":0.01,"8":0.18,"9":0.62,"10":1.46,"11":2.83,"12":4.57,"13":6.81,"14":8.94,"15":9.88,"16":10.12,"17":10.14}},{"date":"2025-06-09","day_of_week":"Monday","total_solar_kwh":11.91,"max_battery_soc_kwh":11.43,"battery_filled_pct":41.8,"time_to_full":null,"hourly_soc":{"7":0.02,"8":0.27,"9":0.71,"10":1.65,"11":3.29,"12":5.01,"13":7.26,"14":9.62,"15":10.83,"16":11.34,"17":11.43}},{"date":"2025-06-10","day_of_week":"Tuesday","total_solar_kwh":11.2,"max_battery_soc_kwh":10.75,"battery_filled_pct":39.3,"time_to_full":null,"hourly_soc":{"7":0.01,"8":0.24,"9":0.79,"10":1.65,"11":2.83,"12":5.06,"13":7.58,"14":9.5,"15":10.55,"16":10.73,"17":10.75}},{"date":"2025-06-11","day_of_week":"Wednesday","total_solar_kwh":7.56,"max_battery_soc_kwh":7.26,"battery_filled_pct":26.5,"time_to_full":null,"hourly_soc":{"7":0.01,"8":0.15,"9":0.68,"10":1.73,"11":3.21,"12":4.52,"13":5.42,"14":6.21,"15":7.05,"16":7.24,"17":7.26}},{"date":"2025-06-12","day_of_week":"Thursday","total_solar_kwh":11.34,"max_battery_soc_kwh":10.89,"battery_filled_pct":39.8,"time_to_full":null,"hourly_soc":{"7":0.01,"8":0.06,"9":0.31,"10":1.1,"11":2.76,"12":4.99,"13":7.52,"14":9.69,"15":10.7,"16":10.86,"17":10.88}},{"date":"2025-06-13","day_of_week":"Friday","total_solar_kwh":11.4,"max_battery_soc_kwh":10.95,"battery_filled_pct":40.0,"time_to_full":null,"hourly_soc":{"7":0.0,"8":0.06,"9":0.26,"10":1.05,"11":2.68,"12":4.94,"13":7.55,"14":9.82,"15":10.8,"16":10.93,"17":10.94}},{"date":"2025-06-14","day_of_week":"Saturday","total_solar_kwh":4.06,"max_battery_soc_kwh":3.9,"battery_filled_pct":14.3,"time_to_full":null,"hourly_soc":{"7":0.01,"8":0.16,"9":0.6,"10":1.28,"11":1.93,"12":2.34,"13":2.87,"14":3.3,"15":3.64,"16":3.82,"17":3.9}},{"date":"2025-06-15","day_of_week":"Sunday","total_solar_kwh":12.29,"max_battery_soc_kwh":11.8,"battery_filled_pct":43.1,"time_to_full":null,"hourly_soc":{"7":0.01,"8":0.2,"9":0.72,"10":1.81,"11":3.5,"12":5.78,"13":8.38,"14":10.56,"15":11.57,"16":11.77,"17":11.8}},{"date":"2025-06-16","day_of_week":"Monday","total_solar_kwh":11.2,"max_battery_soc_kwh":10.75,"battery_filled_pct":39.3,"time_to_full":null,"hourly_soc":{"7":0.01,"8":0.13,"9":0.56,"10":1.43,"11":3.17,"12":5.44,"13":7.5,"14":9.45,"15":10.43,"16":10.71,"17":10.75}},{"date":"2025-06-17","day_of_week":"Tuesday","total_solar_kwh":9.07,"max_battery_soc_kwh":8.7,"battery_filled_pct":31.8,"time_to_full":null,"hourly_soc":{"7":0.01,"8":0.12,"9":0.37,"10":1.12,"11":2.52,"12":4.61,"13":6.0,"14":7.53,"15":8.54,"16":8.68,"17":8.7}},{"date":"2025-06-18","day_of_week":"Wednesday","total_solar_kwh":8.96,"max_battery_soc_kwh":8.6,"battery_filled_pct":31.4,"time_to_full":null,"hourly_soc":{"7":0.01,"8":0.21,"9":0.71,"10":1.66,"11":3.17,"12":4.92,"13":6.29,"14":7.37,"15":8.19,"16":8.57,"17":8.6}},{"date":"2025-06-19","day_of_week":"Thursday","total_solar_kwh":9.92,"max_battery_soc_kwh":9.52,"battery_filled_pct":34.8,"time_to_full":null,"hourly_soc":{"7":0.01,"8":0.11,"9":0.46,"10":1.25,"11":2.58,"12":4.51,"13":6.35,"14":8.04,"15":9.2,"16":9.47,"17":9.52}},{"date":"2025-06-20","day_of_week":"Friday","total_solar_kwh":11.28,"max_battery_soc_kwh":10.83,"battery_filled_pct":39.6,"time_to_full":null,"hourly_soc":{"7":0.01,"8":0.11,"9":0.34,"10":1.09,"11":2.67,"12":4.87,"13":7.43,"14":9.67,"15":10.67,"16":10.81,"17":10.83}},{"date":"2025-06-21","day_of_week":"Saturday","total_solar_kwh":11.29,"max_battery_soc_kwh":10.84,"battery_filled_pct":39.6,"time_to_full":null,"hourly_soc":{"7":0.01,"8":0.09,"9":0.32,"10":1.08,"11":2.67,"12":4.89,"13":7.46,"14":9.71,"15":10.7,"16":10.82,"17":10.84}},{"date":"2025-06-22","day_of_week":"Sunday","total_solar_kwh":9.76,"max_battery_soc_kwh":9.37,"battery_filled_pct":34.3,"time_to_full":null,"hourly_soc":{"7":0.01,"8":0.12,"9":0.4,"10":1.14,"11":2.48,"12":3.79,"13":5.86,"14":8.28,"15":9.16,"16":9.36,"17":9.37}},{"date":"2025-06-23","day_of_week":"Monday","total_solar_kwh":11.67,"max_battery_soc_kwh":11.21,"battery_filled_pct":41.0,"time_to_full":null,"hourly_soc":{"7":0.01,"8":0.09,"9":0.32,"10":1.06,"11":2.65,"12":4.87,"13":7.48,"14":9.78,"15":10.83,"16":11.14,"17":11.2}},{"date":"2025-06-24","day_of_week":"Tuesday","total_solar_kwh":5.84,"max_battery_soc_kwh":5.61,"battery_filled_pct":20.5,"time_to_full":null,"hourly_soc":{"7":0.01,"8":0.11,"9":0.45,"10":1.21,"11":2.41,"12":3.08,"13":3.82,"14":4.61,"15":5.22,"16":5.52,"17":5.6}},{"date":"2025-06-25","day_of_week":"Wednesday","total_solar_kwh":10.78,"max_battery_soc_kwh":10.35,"battery_filled_pct":37.8,"time_to_full":null,"hourly_soc":{"7":0.01,"8":0.14,"9":0.5,"10":1.22,"11":2.65,"12":4.71,"13":6.69,"14":8.62,"15":9.93,"16":10.3,"17":10.34}},{"date":"2025-06-26","day_of_week":"Thursday","total_solar_kwh":6.65,"max_battery_soc_kwh":6.38,"battery_filled_pct":23.3,"time_to_full":null,"hourly_soc":{"7":0.01,"8":0.16,"9":0.66,"10":1.68,"11":3.22,"12":4.38,"13":5.27,"14":5.6,"15":5.96,"16":6.32,"17":6.38}},{"date":"2025-06-27","day_of_week":"Friday","total_solar_kwh":7.33,"max_battery_soc_kwh":7.04,"battery_filled_pct":25.7,"time_to_full":null,"hourly_soc":{"7":0.0,"8":0.11,"9":0.59,"10":1.48,"11":2.89,"12":3.85,"13":4.64,"14":5.66,"15":6.5,"16":6.96,"17":7.03}},{"date":"2025-06-28","day_of_week":"Saturday","total_solar_kwh":8.26,"max_battery_soc_kwh":7.93,"battery_filled_pct":29.0,"time_to_full":null,"hourly_soc":{"7":0.01,"8":0.09,"9":0.51,"10":1.45,"11":2.58,"12":3.78,"13":5.12,"14":6.66,"15":7.56,"16":7.9,"17":7.93}},{"date":"2025-06-29","day_of_week":"Sunday","total_solar_kwh":11.18,"max_battery_soc_kwh":10.73,"battery_filled_pct":39.2,"time_to_full":null,"hourly_soc":{"7":0.01,"8":0.11,"9":0.59,"10":1.6,"11":3.17,"12":5.23,"13":7.83,"14":9.64,"15":10.35,"16":10.65,"17":10.73}},{"date":"2025-06-30","day_of_week":"Monday","total_solar_kwh":11.01,"max_battery_soc_kwh":10.57,"battery_filled_pct":38.6,"time_to_full":null,"hourly_soc":{"7":0.01,"8":0.14,"9":0.44,"10":1.23,"11":2.85,"12":5.13,"13":7.24,"14":9.3,"15":10.36,"16":10.54,"17":10.57}},{"date":"2025-07-01","day_of_week":"Tuesday","total_solar_kwh":10.1,"max_battery_soc_kwh":9.69,"battery_filled_pct":35.4,"time_to_full":null,"hourly_soc":{"7":0.01,"8":0.09,"9":0.33,"10":1.11,"11":2.7,"12":4.87,"13":7.52,"14":8.89,"15":9.34,"16":9.63,"17":9.69}},{"date":"2025-07-02","day_of_week":"Wednesday","total_solar_kwh":6.22,"max_battery_soc_kwh":5.98,"battery_filled_pct":21.8,"time_to_full":null,"hourly_soc":{"7":0.01,"8":0.15,"9":0.63,"10":1.21,"11":1.83,"12":2.56,"13":3.54,"14":4.84,"15":5.77,"16":5.95,"17":5.97}},{"date":"2025-07-03","day_of_week":"Thursday","total_solar_kwh":11.28,"max_battery_soc_kwh":10.83,"battery_filled_pct":39.6,"time_to_full":null,"hourly_soc":{"7":0.01,"8":0.15,"9":0.41,"10":1.16,"11":2.78,"12":4.95,"13":7.28,"14":9.42,"15":10.48,"16":10.78,"17":10.83}},{"date":"2025-07-04","day_of_week":"Friday","total_solar_kwh":8.85,"max_battery_soc_kwh":8.49,"battery_filled_pct":31.0,"time_to_full":null,"hourly_soc":{"7":0.01,"8":0.21,"9":0.78,"10":1.75,"11":3.24,"12":5.1,"13":6.24,"14":7.31,"15":8.0,"16":8.39,"17":8.49}},{"date":"2025-07-05","day_of_week":"Saturday","total_solar_kwh":9.68,"max_battery_soc_kwh":9.29,"battery_filled_pct":34.0,"time_to_full":null,"hourly_soc":{"7":0.01,"8":0.12,"9":0.62,"10":1.14,"11":1.83,"12":3.05,"13":5.08,"14":7.61,"15":8.86,"16":9.2,"17":9.29}},{"date":"2025-07-06","day_of_week":"Sunday","total_solar_kwh":9.39,"max_battery_soc_kwh":9.01,"battery_filled_pct":32.9,"time_to_full":null,"hourly_soc":{"7":0.01,"8":0.14,"9":0.44,"10":1.19,"11":2.52,"12":4.1,"13":6.03,"14":7.74,"15":8.82,"16":8.98,"17":9.01}},{"date":"2025-07-07","day_of_week":"Monday","total_solar_kwh":10.15,"max_battery_soc_kwh":9.74,"battery_filled_pct":35.6,"time_to_full":null,"hourly_soc":{"7":0.01,"8":0.14,"9":0.59,"10":1.36,"11":2.68,"12":4.2,"13":6.1,"14":7.83,"15":9.18,"16":9.68,"17":9.74}},{"date":"2025-07-08","day_of_week":"Tuesday","total_solar_kwh":7.95,"max_battery_soc_kwh":7.64,"battery_filled_pct":27.9,"time_to_full":null,"hourly_soc":{"7":0.0,"8":0.08,"9":0.46,"10":1.22,"11":2.24,"12":3.61,"13":5.2,"14":6.4,"15":7.26,"16":7.59,"17":7.63}},{"date":"2025-07-09","day_of_week":"Wednesday","total_solar_kwh":2.93,"max_battery_soc_kwh":2.82,"battery_filled_pct":10.3,"time_to_full":null,"hourly_soc":{"7":0.0,"8":0.07,"9":0.42,"10":0.9,"11":1.21,"12":1.43,"13":1.88,"14":2.32,"15":2.68,"16":2.8,"17":2.81}},{"date":"2025-07-10","day_of_week":"Thursday","total_solar_kwh":9.8,"max_battery_soc_kwh":9.41,"battery_filled_pct":34.4,"time_to_full":null,"hourly_soc":{"7":0.01,"8":0.14,"9":0.5,"10":1.4,"11":2.91,"12":5.08,"13":6.71,"14":7.85,"15":8.87,"16":9.33,"17":9.41}},{"date":"2025-07-11","day_of_week":"Friday","total_solar_kwh":12.34,"max_battery_soc_kwh":11.85,"battery_filled_pct":43.3,"time_to_full":null,"hourly_soc":{"7":0.01,"8":0.16,"9":0.66,"10":1.63,"11":3.24,"12":5.44,"13":7.76,"14":9.89,"15":11.14,"16":11.72,"17":11.85}},{"date":"2025-07-12","day_of_week":"Saturday","total_solar_kwh":10.15,"max_battery_soc_kwh":9.74,"battery_filled_pct":35.6,"time_to_full":null,"hourly_soc":{"7":0.01,"8":0.07,"9":0.31,"10":1.1,"11":2.75,"12":4.98,"13":6.62,"14":8.09,"15":9.1,"16":9.6,"17":9.74}},{"date":"2025-07-13","day_of_week":"Sunday","total_solar_kwh":6.53,"max_battery_soc_kwh":6.27,"battery_filled_pct":22.9,"time_to_full":null,"hourly_soc":{"7":0.01,"8":0.17,"9":0.76,"10":1.72,"11":2.52,"12":3.19,"13":3.61,"14":4.6,"15":5.66,"16":6.18,"17":6.26}},{"date":"2025-07-14","day_of_week":"Monday","total_solar_kwh":9.96,"max_battery_soc_kwh":9.56,"battery_filled_pct":34.9,"time_to_full":null,"hourly_soc":{"7":0.01,"8":0.22,"9":0.69,"10":1.84,"11":3.33,"12":5.16,"13":7.26,"14":8.61,"15":9.3,"16":9.53,"17":9.56}},{"date":"2025-07-15","day_of_week":"Tuesday","total_solar_kwh":10.57,"max_battery_soc_kwh":10.14,"battery_filled_pct":37.1,"time_to_full":null,"hourly_soc":{"7":0.0,"8":0.14,"9":0.48,"10":1.3,"11":2.74,"12":4.68,"13":7.2,"14":8.8,"15":9.76,"16":10.1,"17":10.14}},{"date":"2025-07-16","day_of_week":"Wednesday","total_solar_kwh":12.92,"max_battery_soc_kwh":12.4,"battery_filled_pct":45.3,"time_to_full":null,"hourly_soc":{"7":0.0,"8":0.06,"9":0.39,"10":1.11,"11":2.82,"12":5.23,"13":8.06,"14":10.62,"15":11.89,"16":12.31,"17":12.4}},{"date":"2025-07-17","day_of_week":"Thursday","total_solar_kwh":12.49,"max_battery_soc_kwh":11.99,"battery_filled_pct":43.8,"time_to_full":null,"hourly_soc":{"7":0.0,"8":0.1,"9":0.52,"10":1.46,"11":2.75,"12":4.93,"13":7.69,"14":10.28,"15":11.6,"16":11.93,"17":11.98}},{"date":"2025-07-18","day_of_week":"Friday","total_solar_kwh":13.04,"max_battery_soc_kwh":12.51,"battery_filled_pct":45.7,"time_to_full":null,"hourly_soc":{"7":0.01,"8":0.15,"9":0.49,"10":1.42,"11":3.25,"12":5.63,"13":8.18,"14":10.77,"15":12.05,"16":12.41,"17":12.51}},{"date":"2025-07-19","day_of_week":"Saturday","total_solar_kwh":8.85,"max_battery_soc_kwh":8.5,"battery_filled_pct":31.1,"time_to_full":null,"hourly_soc":{"7":0.01,"8":0.16,"9":0.74,"10":1.68,"11":2.93,"12":4.79,"13":6.49,"14":7.38,"15":8.02,"16":8.41,"17":8.5}},{"date":"2025-07-20","day_of_week":"Sunday","total_solar_kwh":12.21,"max_battery_soc_kwh":11.72,"battery_filled_pct":42.8,"time_to_full":null,"hourly_soc":{"7":0.01,"8":0.18,"9":0.69,"10":1.65,"11":3.41,"12":5.86,"13":8.68,"14":10.56,"15":11.27,"16":11.65,"17":11.72}},{"date":"2025-07-21","day_of_week":"Monday","total_solar_kwh":12.48,"max_battery_soc_kwh":11.98,"battery_filled_pct":43.8,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.01,"8":0.11,"9":0.38,"10":1.28,"11":3.13,"12":5.65,"13":8.43,"14":10.78,"15":11.7,"16":11.95,"17":11.98}},{"date":"2025-07-22","day_of_week":"Tuesday","total_solar_kwh":12.04,"max_battery_soc_kwh":11.56,"battery_filled_pct":42.3,"time_to_full":null,"hourly_soc":{"7":0.01,"8":0.22,"9":0.78,"10":1.75,"11":3.53,"12":5.32,"13":7.83,"14":10.07,"15":11.04,"16":11.47,"17":11.56}},{"date":"2025-07-23","day_of_week":"Wednesday","total_solar_kwh":13.56,"max_battery_soc_kwh":13.02,"battery_filled_pct":47.6,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.01,"8":0.15,"9":0.56,"10":1.55,"11":3.26,"12":5.66,"13":8.58,"14":11.31,"15":12.68,"16":12.98,"17":13.01}},{"date":"2025-07-24","day_of_week":"Thursday","total_solar_kwh":11.94,"max_battery_soc_kwh":11.46,"battery_filled_pct":41.9,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.01,"8":0.12,"9":0.66,"10":1.74,"11":3.53,"12":5.78,"13":8.24,"14":9.72,"15":11.06,"16":11.43,"17":11.46}},{"date":"2025-07-25","day_of_week":"Friday","total_solar_kwh":1.98,"max_battery_soc_kwh":1.9,"battery_filled_pct":6.9,"time_to_full":null,"hourly_soc":{"7":0.0,"8":0.02,"9":0.06,"10":0.16,"11":0.28,"12":0.52,"13":0.97,"14":1.39,"15":1.72,"16":1.87,"17":1.89}},{"date":"2025-07-26","day_of_week":"Saturday","total_solar_kwh":10.34,"max_battery_soc_kwh":9.88,"battery_filled_pct":36.1,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.02,"8":0.26,"9":0.83,"10":1.8,"11":3.19,"12":5.13,"13":7.67,"14":9.01,"15":9.53,"16":9.81,"17":9.88}},{"date":"2025-07-27","day_of_week":"Sunday","total_solar_kwh":11.89,"max_battery_soc_kwh":11.41,"battery_filled_pct":41.7,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.01,"8":0.13,"9":0.69,"10":1.73,"11":3.22,"12":5.38,"13":7.43,"14":9.57,"15":10.62,"16":11.25,"17":11.4,"18":11.41}},{"date":"2025-07-28","day_of_week":"Monday","total_solar_kwh":13.8,"max_battery_soc_kwh":13.25,"battery_filled_pct":48.4,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.01,"8":0.15,"9":0.8,"10":1.86,"11":3.79,"12":6.07,"13":8.2,"14":10.83,"15":12.34,"16":13.04,"17":13.25,"18":13.25}},{"date":"2025-07-29","day_of_week":"Tuesday","total_solar_kwh":5.62,"max_battery_soc_kwh":5.4,"battery_filled_pct":19.7,"time_to_full":null,"hourly_soc":{"7":0.01,"8":0.1,"9":0.34,"10":1.03,"11":2.0,"12":3.11,"13":4.12,"14":4.73,"15":5.04,"16":5.27,"17":5.39,"18":5.4}},{"date":"2025-07-30","day_of_week":"Wednesday","total_solar_kwh":11.79,"max_battery_soc_kwh":11.32,"battery_filled_pct":41.4,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.04,"8":0.3,"9":0.93,"10":2.11,"11":3.94,"12":5.74,"13":7.56,"14":8.98,"15":10.44,"16":11.12,"17":11.31,"18":11.32}},{"date":"2025-07-31","day_of_week":"Thursday","total_solar_kwh":13.2,"max_battery_soc_kwh":12.68,"battery_filled_pct":46.3,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.01,"8":0.12,"9":0.43,"10":1.44,"11":2.93,"12":5.23,"13":8.02,"14":10.91,"15":12.13,"16":12.55,"17":12.67,"18":12.68}},{"date":"2025-08-01","day_of_week":"Friday","total_solar_kwh":12.77,"max_battery_soc_kwh":12.25,"battery_filled_pct":44.8,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.01,"8":0.13,"9":0.47,"10":1.73,"11":3.87,"12":6.17,"13":8.32,"14":10.44,"15":11.64,"16":12.14,"17":12.24,"18":12.25}},{"date":"2025-08-02","day_of_week":"Saturday","total_solar_kwh":10.89,"max_battery_soc_kwh":10.45,"battery_filled_pct":38.2,"time_to_full":null,"hourly_soc":{"7":0.01,"8":0.16,"9":0.79,"10":1.87,"11":3.2,"12":4.33,"13":5.91,"14":8.24,"15":9.9,"16":10.39,"17":10.45,"18":10.45}},{"date":"2025-08-03","day_of_week":"Sunday","total_solar_kwh":15.73,"max_battery_soc_kwh":15.1,"battery_filled_pct":55.2,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.01,"8":0.14,"9":0.45,"10":1.51,"11":3.59,"12":6.36,"13":9.56,"14":12.69,"15":14.39,"16":14.98,"17":15.1,"18":15.1}},{"date":"2025-08-04","day_of_week":"Monday","total_solar_kwh":3.97,"max_battery_soc_kwh":3.81,"battery_filled_pct":13.9,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.01,"8":0.1,"9":0.28,"10":0.68,"11":1.08,"12":1.76,"13":2.41,"14":2.9,"15":3.25,"16":3.64,"17":3.81,"18":3.81}},{"date":"2025-08-05","day_of_week":"Tuesday","total_solar_kwh":15.92,"max_battery_soc_kwh":15.28,"battery_filled_pct":55.8,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.01,"8":0.31,"9":1.08,"10":2.21,"11":4.14,"12":6.95,"13":10.09,"14":13.11,"15":14.74,"16":15.2,"17":15.27,"18":15.28}},{"date":"2025-08-06","day_of_week":"Wednesday","total_solar_kwh":14.8,"max_battery_soc_kwh":14.21,"battery_filled_pct":51.9,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.01,"8":0.13,"9":0.65,"10":1.78,"11":3.64,"12":6.19,"13":9.08,"14":11.75,"15":13.36,"16":13.96,"17":14.2,"18":14.21}},{"date":"2025-08-07","day_of_week":"Thursday","total_solar_kwh":14.31,"max_battery_soc_kwh":13.74,"battery_filled_pct":50.2,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.03,"8":0.26,"9":0.7,"10":1.88,"11":4.05,"12":6.69,"13":8.41,"14":10.86,"15":12.81,"16":13.6,"17":13.73,"18":13.74}},{"date":"2025-08-08","day_of_week":"Friday","total_solar_kwh":16.21,"max_battery_soc_kwh":15.56,"battery_filled_pct":56.9,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.02,"8":0.16,"9":0.56,"10":1.8,"11":4.03,"12":6.93,"13":10.19,"14":13.33,"15":15.02,"16":15.49,"17":15.55,"18":15.56}},{"date":"2025-08-09","day_of_week":"Saturday","total_solar_kwh":12.86,"max_battery_soc_kwh":12.29,"battery_filled_pct":44.9,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.03,"8":0.23,"9":0.8,"10":2.09,"11":3.91,"12":5.85,"13":7.98,"14":9.88,"15":11.48,"16":12.11,"17":12.28,"18":12.29}},{"date":"2025-08-10","day_of_week":"Sunday","total_solar_kwh":11.44,"max_battery_soc_kwh":10.95,"battery_filled_pct":40.0,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.02,"8":0.14,"9":0.46,"10":1.2,"11":2.89,"12":4.63,"13":7.11,"14":8.76,"15":10.02,"16":10.75,"17":10.94,"18":10.95}},{"date":"2025-08-11","day_of_week":"Monday","total_solar_kwh":12.38,"max_battery_soc_kwh":11.88,"battery_filled_pct":43.4,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.02,"8":0.27,"9":0.94,"10":2.05,"11":4.04,"12":6.23,"13":7.6,"14":9.36,"15":10.95,"16":11.62,"17":11.87,"18":11.88}},{"date":"2025-08-12","day_of_week":"Tuesday","total_solar_kwh":16.46,"max_battery_soc_kwh":15.8,"battery_filled_pct":57.7,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.03,"8":0.3,"9":1.02,"10":2.45,"11":4.72,"12":7.46,"13":10.7,"14":13.46,"15":15.18,"16":15.72,"17":15.79,"18":15.8}},{"date":"2025-08-13","day_of_week":"Wednesday","total_solar_kwh":14.78,"max_battery_soc_kwh":14.17,"battery_filled_pct":51.8,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.03,"8":0.27,"9":0.84,"10":2.13,"11":4.43,"12":6.16,"13":8.84,"14":11.74,"15":13.53,"16":14.08,"17":14.16,"18":14.17}},{"date":"2025-08-14","day_of_week":"Thursday","total_solar_kwh":17.18,"max_battery_soc_kwh":16.49,"battery_filled_pct":60.3,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.02,"8":0.17,"9":0.58,"10":1.86,"11":4.18,"12":7.16,"13":10.28,"14":13.54,"15":15.42,"16":16.26,"17":16.48,"18":16.49}},{"date":"2025-08-15","day_of_week":"Friday","total_solar_kwh":14.78,"max_battery_soc_kwh":14.19,"battery_filled_pct":51.9,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.05,"8":0.31,"9":0.85,"10":2.23,"11":4.45,"12":6.59,"13":9.34,"14":11.62,"15":13.38,"16":14.0,"17":14.17,"18":14.19}},{"date":"2025-08-16","day_of_week":"Saturday","total_solar_kwh":13.85,"max_battery_soc_kwh":13.3,"battery_filled_pct":48.6,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.04,"8":0.29,"9":0.77,"10":1.93,"11":3.79,"12":5.9,"13":8.31,"14":11.15,"15":12.54,"16":13.09,"17":13.29,"18":13.3}},{"date":"2025-08-17","day_of_week":"Sunday","total_solar_kwh":17.96,"max_battery_soc_kwh":17.18,"battery_filled_pct":62.8,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.03,"8":0.3,"9":0.96,"10":2.45,"11":4.81,"12":7.83,"13":11.14,"14":14.18,"15":16.28,"16":16.93,"17":17.12,"18":17.18}},{"date":"2025-08-18","day_of_week":"Monday","total_solar_kwh":15.71,"max_battery_soc_kwh":14.94,"battery_filled_pct":54.6,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.03,"8":0.18,"9":0.64,"10":2.05,"11":4.43,"12":6.99,"13":9.75,"14":12.55,"15":14.26,"16":14.85,"17":14.93,"18":14.94}},{"date":"2025-08-19","day_of_week":"Tuesday","total_solar_kwh":18.03,"max_battery_soc_kwh":17.31,"battery_filled_pct":63.3,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.03,"8":0.21,"9":0.73,"10":2.19,"11":4.69,"12":7.71,"13":11.1,"14":14.63,"15":16.64,"16":17.24,"17":17.3,"18":17.31}},{"date":"2025-08-20","day_of_week":"Wednesday","total_solar_kwh":18.16,"max_battery_soc_kwh":17.43,"battery_filled_pct":63.7,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.03,"8":0.2,"9":0.68,"10":2.11,"11":4.58,"12":7.72,"13":11.26,"14":14.77,"15":16.76,"16":17.37,"17":17.42,"18":17.43}},{"date":"2025-08-21","day_of_week":"Thursday","total_solar_kwh":12.75,"max_battery_soc_kwh":12.24,"battery_filled_pct":44.7,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.07,"8":0.61,"9":1.46,"10":2.5,"11":3.92,"12":5.63,"13":7.76,"14":9.97,"15":11.35,"16":12.01,"17":12.23,"18":12.24}},{"date":"2025-08-22","day_of_week":"Friday","total_solar_kwh":16.49,"max_battery_soc_kwh":15.81,"battery_filled_pct":57.8,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.02,"8":0.17,"9":0.77,"10":1.64,"11":3.22,"12":6.24,"13":9.49,"14":12.9,"15":14.97,"16":15.68,"17":15.8,"18":15.81}},{"date":"2025-08-23","day_of_week":"Saturday","total_solar_kwh":18.95,"max_battery_soc_kwh":18.2,"battery_filled_pct":66.5,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.05,"8":0.36,"9":1.01,"10":2.38,"11":5.05,"12":8.24,"13":11.87,"14":15.42,"15":17.45,"16":18.11,"17":18.18,"18":18.19}},{"date":"2025-08-24","day_of_week":"Sunday","total_solar_kwh":9.84,"max_battery_soc_kwh":9.44,"battery_filled_pct":34.5,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.04,"8":0.28,"9":0.87,"10":2.35,"11":4.09,"12":5.51,"13":6.81,"14":8.13,"15":8.71,"16":9.24,"17":9.43,"18":9.44}},{"date":"2025-08-25","day_of_week":"Monday","total_solar_kwh":2.66,"max_battery_soc_kwh":2.55,"battery_filled_pct":9.3,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.03,"8":0.12,"9":0.33,"10":0.72,"11":1.17,"12":1.7,"13":2.15,"14":2.36,"15":2.45,"16":2.52,"17":2.55,"18":2.55}},{"date":"2025-08-26","day_of_week":"Tuesday","total_solar_kwh":18.92,"max_battery_soc_kwh":18.17,"battery_filled_pct":66.4,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.03,"8":0.32,"9":1.11,"10":2.42,"11":4.82,"12":8.11,"13":11.82,"14":15.21,"15":17.29,"16":18.03,"17":18.15,"18":18.16}},{"date":"2025-08-27","day_of_week":"Wednesday","total_solar_kwh":17.39,"max_battery_soc_kwh":16.6,"battery_filled_pct":60.7,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.06,"8":0.46,"9":1.43,"10":2.97,"11":4.77,"12":6.91,"13":9.69,"14":13.39,"15":15.57,"16":16.36,"17":16.58,"18":16.6}},{"date":"2025-08-28","day_of_week":"Thursday","total_solar_kwh":10.04,"max_battery_soc_kwh":9.53,"battery_filled_pct":34.8,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.09,"8":0.3,"9":0.75,"10":1.33,"11":2.68,"12":3.51,"13":4.43,"14":6.62,"15":8.22,"16":9.19,"17":9.51,"18":9.53}},{"date":"2025-08-29","day_of_week":"Friday","total_solar_kwh":12.52,"max_battery_soc_kwh":12.02,"battery_filled_pct":43.9,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.03,"8":0.33,"9":1.15,"10":2.84,"11":5.01,"12":7.18,"13":8.01,"14":9.5,"15":11.03,"16":11.67,"17":12.0,"18":12.02}},{"date":"2025-08-30","day_of_week":"Saturday","total_solar_kwh":13.23,"max_battery_soc_kwh":12.58,"battery_filled_pct":46.0,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.11,"8":0.45,"9":1.23,"10":2.57,"11":4.17,"12":6.11,"13":7.98,"14":9.85,"15":11.39,"16":12.23,"17":12.54,"18":12.58}},{"date":"2025-08-31","day_of_week":"Sunday","total_solar_kwh":14.99,"max_battery_soc_kwh":14.19,"battery_filled_pct":51.9,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.11,"8":0.62,"9":1.52,"10":2.61,"11":4.33,"12":6.45,"13":9.0,"14":11.32,"15":12.88,"16":13.85,"17":14.17,"18":14.19}},{"date":"2025-09-01","day_of_week":"Monday","total_solar_kwh":17.57,"max_battery_soc_kwh":16.56,"battery_filled_pct":60.5,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.12,"8":0.64,"9":1.59,"10":2.53,"11":4.06,"12":6.69,"13":9.94,"14":13.36,"15":15.36,"16":16.29,"17":16.54,"18":16.56}},{"date":"2025-09-02","day_of_week":"Tuesday","total_solar_kwh":21.46,"max_battery_soc_kwh":20.6,"battery_filled_pct":75.3,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.09,"8":0.35,"9":1.13,"10":2.99,"11":5.84,"12":9.32,"13":13.13,"14":16.94,"15":19.15,"16":20.22,"17":20.57,"18":20.6}},{"date":"2025-09-03","day_of_week":"Wednesday","total_solar_kwh":20.64,"max_battery_soc_kwh":19.59,"battery_filled_pct":71.6,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.19,"8":0.9,"9":1.69,"10":3.32,"11":6.08,"12":8.88,"13":12.53,"14":15.9,"15":18.3,"16":19.33,"17":19.57,"18":19.59}},{"date":"2025-09-04","day_of_week":"Thursday","total_solar_kwh":20.69,"max_battery_soc_kwh":19.84,"battery_filled_pct":72.5,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.1,"8":0.7,"9":1.55,"10":3.13,"11":5.31,"12":8.56,"13":12.56,"14":16.54,"15":18.87,"16":19.72,"17":19.83,"18":19.84}},{"date":"2025-09-05","day_of_week":"Friday","total_solar_kwh":16.05,"max_battery_soc_kwh":15.39,"battery_filled_pct":56.3,"time_to_full":null,"hourly_soc":{"6":0.01,"7":0.14,"8":0.74,"9":1.84,"10":3.67,"11":5.51,"12":7.64,"13":9.62,"14":12.14,"15":14.38,"16":15.22,"17":15.37,"18":15.39}},{"date":"2025-09-06","day_of_week":"Saturday","total_solar_kwh":10.05,"max_battery_soc_kwh":9.65,"battery_filled_pct":35.3,"time_to_full":null,"hourly_soc":{"6":0.0,"7":0.04,"8":0.39,"9":1.0,"10":2.06,"11":3.66,"12":5.03,"13":6.28,"14":7.62,"15":8.72,"16":9.34,"17":9.63,"18":9.65}},{"date":"2025-09-07","day_of_week":"Sunday","total_solar_kwh":20.92,"max_battery_soc_kwh":20.08,"battery_filled_pct":73.4,"time_to_full":null,"hourly_soc":{"6":0.01,"7":0.16,"8":0.64,"9":1.56,"10":2.83,"11":5.3,"12":8.94,"13":12.94,"14":16.85,"15":19.13,"16":19.98,"17":20.07,"18":20.08}},{"date":"2025-09-08","day_of_week":"Monday","total_solar_kwh":22.85,"max_battery_soc_kwh":21.93,"battery_filled_pct":80.2,"time_to_full":null,"hourly_soc":{"6":0.01,"7":0.15,"8":0.71,"9":1.72,"10":3.86,"11":6.95,"12":10.64,"13":14.68,"14":18.63,"15":20.95,"16":21.82,"17":21.92,"18":21.93}},{"date":"2025-09-09","day_of_week":"Tuesday","total_solar_kwh":9.81,"max_battery_soc_kwh":9.41,"battery_filled_pct":34.4,"time_to_full":null,"hourly_soc":{"6":0.01,"7":0.14,"8":0.52,"9":1.31,"10":2.69,"11":4.24,"12":5.86,"13":6.68,"14":7.84,"15":8.67,"16":9.26,"17":9.39,"18":9.41}},{"date":"2025-09-10","day_of_week":"Wednesday","total_solar_kwh":20.5,"max_battery_soc_kwh":19.18,"battery_filled_pct":70.1,"time_to_full":null,"hourly_soc":{"6":0.01,"7":0.21,"8":0.64,"9":1.65,"10":3.22,"11":5.29,"12":8.63,"13":12.48,"14":15.64,"15":18.0,"16":19.03,"17":19.16,"18":19.18}},{"date":"2025-09-11","day_of_week":"Thursday","total_solar_kwh":22.22,"max_battery_soc_kwh":21.07,"battery_filled_pct":77.0,"time_to_full":null,"hourly_soc":{"6":0.01,"7":0.11,"8":0.44,"9":1.46,"10":3.16,"11":5.95,"12":9.61,"13":13.72,"14":17.73,"15":19.98,"16":20.91,"17":21.05,"18":21.07}},{"date":"2025-09-12","day_of_week":"Friday","total_solar_kwh":22.03,"max_battery_soc_kwh":20.5,"battery_filled_pct":74.9,"time_to_full":null,"hourly_soc":{"6":0.01,"7":0.21,"8":0.68,"9":1.79,"10":3.32,"11":5.86,"12":8.8,"13":12.66,"14":16.2,"15":18.85,"16":20.19,"17":20.47,"18":20.5}},{"date":"2025-09-13","day_of_week":"Saturday","total_solar_kwh":23.65,"max_battery_soc_kwh":22.41,"battery_filled_pct":81.9,"time_to_full":null,"hourly_soc":{"6":0.01,"7":0.13,"8":0.48,"9":1.56,"10":3.84,"11":6.95,"12":10.64,"13":14.67,"14":18.66,"15":21.09,"16":22.1,"17":22.35,"18":22.41}},{"date":"2025-09-14","day_of_week":"Sunday","total_solar_kwh":23.47,"max_battery_soc_kwh":22.09,"battery_filled_pct":80.7,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.01,"7":0.13,"8":0.47,"9":1.56,"10":3.87,"11":7.15,"12":11.02,"13":15.14,"14":18.83,"15":21.05,"16":21.97,"17":22.06,"18":22.09}},{"date":"2025-09-15","day_of_week":"Monday","total_solar_kwh":15.63,"max_battery_soc_kwh":14.78,"battery_filled_pct":54.0,"time_to_full":null,"hourly_soc":{"6":0.02,"7":0.24,"8":0.85,"9":1.8,"10":3.17,"11":5.97,"12":7.97,"13":10.03,"14":12.94,"15":14.36,"16":14.67,"17":14.76,"18":14.78}},{"date":"2025-09-16","day_of_week":"Tuesday","total_solar_kwh":22.36,"max_battery_soc_kwh":20.92,"battery_filled_pct":76.5,"time_to_full":null,"hourly_soc":{"6":0.01,"7":0.2,"8":0.69,"9":1.88,"10":4.03,"11":6.96,"12":10.52,"13":14.12,"14":17.26,"15":19.59,"16":20.6,"17":20.89,"18":20.92}},{"date":"2025-09-17","day_of_week":"Wednesday","total_solar_kwh":21.88,"max_battery_soc_kwh":20.69,"battery_filled_pct":75.6,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.01,"7":0.13,"8":0.56,"9":1.61,"10":3.1,"11":5.69,"12":9.51,"13":13.4,"14":16.86,"15":19.4,"16":20.51,"17":20.66,"18":20.69}},{"date":"2025-09-18","day_of_week":"Thursday","total_solar_kwh":24.48,"max_battery_soc_kwh":23.27,"battery_filled_pct":85.0,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.01,"7":0.16,"8":0.55,"9":1.67,"10":3.98,"11":7.24,"12":11.1,"13":15.22,"14":19.27,"15":21.81,"16":22.91,"17":23.19,"18":23.27}},{"date":"2025-09-19","day_of_week":"Friday","total_solar_kwh":24.67,"max_battery_soc_kwh":23.05,"battery_filled_pct":84.2,"time_to_full":null,"hourly_soc":{"6":0.01,"7":0.19,"8":0.74,"9":1.98,"10":4.43,"11":7.61,"12":11.07,"13":14.87,"14":18.75,"15":21.45,"16":22.68,"17":23.0,"18":23.05}},{"date":"2025-09-20","day_of_week":"Saturday","total_solar_kwh":16.68,"max_battery_soc_kwh":16.0,"battery_filled_pct":58.5,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.02,"7":0.22,"8":0.78,"9":2.12,"10":4.43,"11":6.98,"12":9.57,"13":11.65,"14":13.23,"15":14.55,"16":15.55,"17":15.95,"18":16.0}},{"date":"2025-09-21","day_of_week":"Sunday","total_solar_kwh":16.38,"max_battery_soc_kwh":15.54,"battery_filled_pct":56.8,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.01,"7":0.14,"8":0.86,"9":1.9,"10":3.37,"11":5.21,"12":7.25,"13":9.91,"14":12.19,"15":13.88,"16":15.1,"17":15.5,"18":15.54}},{"date":"2025-09-22","day_of_week":"Monday","total_solar_kwh":22.25,"max_battery_soc_kwh":20.48,"battery_filled_pct":74.9,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.02,"7":0.32,"8":1.12,"9":2.45,"10":4.4,"11":7.34,"12":10.65,"13":13.42,"14":16.24,"15":18.94,"16":20.2,"17":20.44,"18":20.48}},{"date":"2025-09-23","day_of_week":"Tuesday","total_solar_kwh":21.78,"max_battery_soc_kwh":20.19,"battery_filled_pct":73.8,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.04,"7":0.36,"8":1.03,"9":2.45,"10":4.55,"11":6.84,"12":9.21,"13":12.5,"14":16.34,"15":18.59,"16":19.73,"17":20.14,"18":20.19}},{"date":"2025-09-24","day_of_week":"Wednesday","total_solar_kwh":23.47,"max_battery_soc_kwh":22.1,"battery_filled_pct":80.8,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.02,"7":0.27,"8":0.98,"9":2.31,"10":4.45,"11":7.01,"12":9.94,"13":13.66,"14":17.63,"15":20.3,"16":21.63,"17":22.05,"18":22.1}},{"date":"2025-09-25","day_of_week":"Thursday","total_solar_kwh":25.39,"max_battery_soc_kwh":23.98,"battery_filled_pct":87.6,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.02,"7":0.22,"8":0.88,"9":2.34,"10":4.69,"11":7.92,"12":11.77,"13":15.87,"14":19.89,"15":22.41,"16":23.67,"17":23.93,"18":23.98}},{"date":"2025-09-26","day_of_week":"Friday","total_solar_kwh":24.52,"max_battery_soc_kwh":23.14,"battery_filled_pct":84.6,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.03,"7":0.26,"8":0.71,"9":2.02,"10":4.47,"11":7.75,"12":11.66,"13":15.44,"14":18.84,"15":21.49,"16":22.82,"17":23.09,"18":23.13}},{"date":"2025-09-27","day_of_week":"Saturday","total_solar_kwh":24.02,"max_battery_soc_kwh":22.09,"battery_filled_pct":80.7,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.05,"7":0.43,"8":1.28,"9":2.86,"10":5.29,"11":8.67,"12":12.2,"13":15.41,"14":17.98,"15":20.28,"16":21.43,"17":22.0,"18":22.09}},{"date":"2025-09-28","day_of_week":"Sunday","total_solar_kwh":22.85,"max_battery_soc_kwh":21.05,"battery_filled_pct":76.9,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.02,"7":0.27,"8":1.02,"9":2.28,"10":4.14,"11":6.66,"12":9.24,"13":13.04,"14":16.92,"15":19.27,"16":20.62,"17":20.97,"18":21.05}},{"date":"2025-09-29","day_of_week":"Monday","total_solar_kwh":13.2,"max_battery_soc_kwh":12.55,"battery_filled_pct":45.9,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.04,"7":0.33,"8":1.04,"9":2.18,"10":3.45,"11":4.63,"12":6.34,"13":8.19,"14":10.36,"15":11.8,"16":12.33,"17":12.53,"18":12.55}},{"date":"2025-09-30","day_of_week":"Tuesday","total_solar_kwh":22.51,"max_battery_soc_kwh":20.52,"battery_filled_pct":75.0,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.04,"7":0.29,"8":0.91,"9":2.42,"10":4.09,"11":6.65,"12":8.58,"13":11.71,"14":15.78,"15":18.6,"16":20.05,"17":20.45,"18":20.52}},{"date":"2025-10-01","day_of_week":"Wednesday","total_solar_kwh":19.48,"max_battery_soc_kwh":18.63,"battery_filled_pct":68.1,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.03,"7":0.34,"8":1.07,"9":2.64,"10":5.1,"11":7.92,"12":11.0,"13":13.47,"14":15.46,"15":16.9,"16":18.06,"17":18.57,"18":18.63}},{"date":"2025-10-02","day_of_week":"Thursday","total_solar_kwh":28.74,"max_battery_soc_kwh":25.73,"battery_filled_pct":94.1,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.05,"7":0.43,"8":1.24,"9":2.92,"10":5.86,"11":9.16,"12":13.12,"13":17.25,"14":21.33,"15":24.01,"16":25.36,"17":25.67,"18":25.73}},{"date":"2025-10-03","day_of_week":"Friday","total_solar_kwh":26.28,"max_battery_soc_kwh":23.61,"battery_filled_pct":86.3,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.04,"7":0.39,"8":1.3,"9":2.73,"10":4.83,"11":7.65,"12":11.31,"13":15.35,"14":19.42,"15":22.09,"16":23.4,"17":23.57,"18":23.6}},{"date":"2025-10-04","day_of_week":"Saturday","total_solar_kwh":27.71,"max_battery_soc_kwh":25.66,"battery_filled_pct":93.8,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.05,"7":0.27,"8":0.81,"9":2.4,"10":5.18,"11":8.83,"12":12.92,"13":17.05,"14":21.12,"15":23.8,"16":25.16,"17":25.59,"18":25.66}},{"date":"2025-10-05","day_of_week":"Sunday","total_solar_kwh":8.83,"max_battery_soc_kwh":8.48,"battery_filled_pct":31.0,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.07,"7":0.56,"8":1.57,"9":3.25,"10":5.13,"11":5.78,"12":6.38,"13":7.12,"14":7.83,"15":8.18,"16":8.33,"17":8.43,"18":8.47}},{"date":"2025-10-06","day_of_week":"Monday","total_solar_kwh":20.08,"max_battery_soc_kwh":19.12,"battery_filled_pct":69.9,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.03,"7":0.31,"8":1.26,"9":2.57,"10":4.26,"11":6.57,"12":9.02,"13":12.03,"14":14.72,"15":16.98,"16":18.44,"17":18.99,"18":19.11}},{"date":"2025-10-07","day_of_week":"Tuesday","total_solar_kwh":22.43,"max_battery_soc_kwh":20.96,"battery_filled_pct":76.6,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.02,"7":0.4,"8":1.46,"9":3.1,"10":4.91,"11":6.83,"12":9.97,"13":13.19,"14":16.67,"15":19.37,"16":20.72,"17":20.92,"18":20.96}},{"date":"2025-10-08","day_of_week":"Wednesday","total_solar_kwh":22.63,"max_battery_soc_kwh":20.72,"battery_filled_pct":75.7,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.08,"7":0.52,"8":1.4,"9":3.0,"10":4.5,"11":6.4,"12":8.96,"13":12.33,"14":16.36,"15":19.11,"16":20.51,"17":20.69,"18":20.72}},{"date":"2025-10-09","day_of_week":"Thursday","total_solar_kwh":29.1,"max_battery_soc_kwh":25.96,"battery_filled_pct":94.9,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.07,"7":0.44,"8":1.2,"9":2.75,"10":5.56,"11":9.03,"12":13.11,"13":17.24,"14":21.33,"15":24.11,"16":25.61,"17":25.9,"18":25.96}},{"date":"2025-10-10","day_of_week":"Friday","total_solar_kwh":27.73,"max_battery_soc_kwh":25.13,"battery_filled_pct":91.8,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.08,"7":0.44,"8":1.28,"9":3.31,"10":6.05,"11":9.26,"12":12.65,"13":16.5,"14":20.47,"15":23.31,"16":24.78,"17":25.06,"18":25.13}},{"date":"2025-10-11","day_of_week":"Saturday","total_solar_kwh":24.41,"max_battery_soc_kwh":22.73,"battery_filled_pct":83.1,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.09,"7":0.6,"8":1.51,"9":3.23,"10":5.61,"11":8.38,"12":11.59,"13":15.02,"14":18.37,"15":20.78,"16":22.24,"17":22.63,"18":22.72}},{"date":"2025-10-12","day_of_week":"Sunday","total_solar_kwh":28.84,"max_battery_soc_kwh":26.03,"battery_filled_pct":95.1,"time_to_full":"17:38","hourly_soc":{"5":0.0,"6":0.1,"7":0.54,"8":1.25,"9":3.04,"10":5.98,"11":9.81,"12":13.93,"13":18.06,"14":21.92,"15":24.17,"16":25.44,"17":25.97,"18":26.02}},{"date":"2025-10-13","day_of_week":"Monday","total_solar_kwh":29.17,"max_battery_soc_kwh":25.66,"battery_filled_pct":93.8,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.1,"7":0.62,"8":1.73,"9":3.24,"10":5.39,"11":8.88,"12":12.86,"13":16.99,"14":21.09,"15":23.91,"16":25.4,"17":25.61,"18":25.65}},{"date":"2025-10-14","day_of_week":"Tuesday","total_solar_kwh":29.88,"max_battery_soc_kwh":26.42,"battery_filled_pct":96.6,"time_to_full":"16:14","hourly_soc":{"5":0.0,"6":0.19,"7":0.73,"8":1.62,"9":3.69,"10":6.29,"11":9.63,"12":13.61,"13":17.74,"14":21.84,"15":24.66,"16":26.15,"17":26.38,"18":26.42}},{"date":"2025-10-15","day_of_week":"Wednesday","total_solar_kwh":29.33,"max_battery_soc_kwh":26.83,"battery_filled_pct":98.1,"time_to_full":"15:59","hourly_soc":{"5":0.0,"6":0.08,"7":0.37,"8":1.16,"9":3.12,"10":6.21,"11":10.08,"12":14.2,"13":18.33,"14":22.42,"15":25.17,"16":26.58,"17":26.79,"18":26.83}},{"date":"2025-10-16","day_of_week":"Thursday","total_solar_kwh":20.36,"max_battery_soc_kwh":19.0,"battery_filled_pct":69.4,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.1,"7":0.57,"8":1.62,"9":3.72,"10":6.37,"11":9.01,"12":10.52,"13":13.06,"14":16.16,"15":18.01,"16":18.66,"17":18.92,"18":19.0}},{"date":"2025-10-17","day_of_week":"Friday","total_solar_kwh":27.86,"max_battery_soc_kwh":25.95,"battery_filled_pct":94.9,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.07,"7":0.33,"8":1.15,"9":2.75,"10":5.23,"11":9.15,"12":13.11,"13":17.08,"14":20.89,"15":23.72,"16":25.29,"17":25.84,"18":25.95}},{"date":"2025-10-18","day_of_week":"Saturday","total_solar_kwh":29.59,"max_battery_soc_kwh":27.2,"battery_filled_pct":99.4,"time_to_full":"15:54","hourly_soc":{"5":0.01,"6":0.13,"7":0.46,"8":1.31,"9":3.35,"10":6.53,"11":10.32,"12":14.44,"13":18.57,"14":22.63,"15":25.37,"16":26.81,"17":27.11,"18":27.2}},{"date":"2025-10-19","day_of_week":"Sunday","total_solar_kwh":10.39,"max_battery_soc_kwh":9.97,"battery_filled_pct":36.5,"time_to_full":null,"hourly_soc":{"5":0.01,"6":0.17,"7":0.44,"8":1.22,"9":2.01,"10":2.97,"11":4.03,"12":5.97,"13":7.05,"14":7.97,"15":8.82,"16":9.48,"17":9.88,"18":9.97}},{"date":"2025-10-20","day_of_week":"Monday","total_solar_kwh":7.14,"max_battery_soc_kwh":6.86,"battery_filled_pct":25.1,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.07,"7":0.47,"8":1.05,"9":1.63,"10":1.99,"11":2.55,"12":3.21,"13":4.2,"14":4.8,"15":5.57,"16":6.52,"17":6.82,"18":6.85}},{"date":"2025-10-21","day_of_week":"Tuesday","total_solar_kwh":5.92,"max_battery_soc_kwh":5.68,"battery_filled_pct":20.8,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.01,"7":0.04,"8":0.09,"9":0.39,"10":0.86,"11":1.28,"12":2.07,"13":3.24,"14":4.19,"15":4.89,"16":5.5,"17":5.64,"18":5.68,"19":5.68}},{"date":"2025-10-22","day_of_week":"Wednesday","total_solar_kwh":26.26,"max_battery_soc_kwh":23.88,"battery_filled_pct":87.3,"time_to_full":null,"hourly_soc":{"5":0.01,"6":0.11,"7":0.6,"8":1.72,"9":3.69,"10":6.02,"11":8.77,"12":12.49,"13":16.26,"14":18.77,"15":21.22,"16":23.03,"17":23.72,"18":23.88,"19":23.88}},{"date":"2025-10-23","day_of_week":"Thursday","total_solar_kwh":28.06,"max_battery_soc_kwh":24.7,"battery_filled_pct":90.3,"time_to_full":null,"hourly_soc":{"5":0.01,"6":0.15,"7":0.72,"8":1.88,"9":3.4,"10":5.53,"11":7.74,"12":11.35,"13":15.48,"14":19.6,"15":22.63,"16":24.32,"17":24.64,"18":24.69,"19":24.7}},{"date":"2025-10-24","day_of_week":"Friday","total_solar_kwh":30.46,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:40","hourly_soc":{"5":0.01,"6":0.11,"7":0.43,"8":1.32,"9":3.43,"10":6.63,"11":10.58,"12":14.71,"13":18.73,"14":22.69,"15":25.62,"16":27.07,"17":27.36,"18":27.36,"19":27.36}},{"date":"2025-10-25","day_of_week":"Saturday","total_solar_kwh":10.98,"max_battery_soc_kwh":10.54,"battery_filled_pct":38.5,"time_to_full":null,"hourly_soc":{"5":0.0,"6":0.06,"7":0.37,"8":1.04,"9":2.1,"10":4.4,"11":6.58,"12":8.51,"13":9.38,"14":9.56,"15":9.89,"16":10.31,"17":10.5,"18":10.54,"19":10.54}},{"date":"2025-10-26","day_of_week":"Sunday","total_solar_kwh":26.28,"max_battery_soc_kwh":23.98,"battery_filled_pct":87.6,"time_to_full":null,"hourly_soc":{"5":0.01,"6":0.16,"7":0.7,"8":1.73,"9":3.47,"10":6.5,"11":10.17,"12":13.6,"13":16.49,"14":19.76,"15":22.12,"16":23.18,"17":23.84,"18":23.97,"19":23.98}},{"date":"2025-10-27","day_of_week":"Monday","total_solar_kwh":17.23,"max_battery_soc_kwh":16.35,"battery_filled_pct":59.8,"time_to_full":null,"hourly_soc":{"5":0.01,"6":0.27,"7":0.84,"8":1.76,"9":3.21,"10":5.5,"11":8.31,"12":9.51,"13":11.23,"14":12.99,"15":14.33,"16":15.43,"17":16.11,"18":16.34,"19":16.35}},{"date":"2025-10-28","day_of_week":"Tuesday","total_solar_kwh":32.8,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:10","hourly_soc":{"5":0.01,"6":0.12,"7":0.45,"8":1.44,"9":3.71,"10":7.12,"11":11.17,"12":15.3,"13":19.43,"14":23.56,"15":26.69,"16":27.36,"17":27.36,"18":27.36,"19":27.36}},{"date":"2025-10-29","day_of_week":"Wednesday","total_solar_kwh":31.08,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:26","hourly_soc":{"5":0.01,"6":0.17,"7":0.53,"8":1.52,"9":3.74,"10":7.06,"11":11.07,"12":15.19,"13":19.09,"14":22.97,"15":26.14,"16":27.35,"17":27.36,"18":27.36,"19":27.36}},{"date":"2025-10-30","day_of_week":"Thursday","total_solar_kwh":16.62,"max_battery_soc_kwh":15.95,"battery_filled_pct":58.3,"time_to_full":null,"hourly_soc":{"5":0.03,"6":0.36,"7":1.07,"8":2.35,"9":4.33,"10":6.23,"11":8.58,"12":10.3,"13":12.65,"14":14.07,"15":14.81,"16":15.48,"17":15.85,"18":15.95,"19":15.95}},{"date":"2025-10-31","day_of_week":"Friday","total_solar_kwh":32.11,"max_battery_soc_kwh":27.36,"battery_filled_pct":100.0,"time_to_full":"15:19","hourly_soc":{"5":0.01,"6":0.15,"7":0.49,"8":1.52,"9":3.76,"10":7.03,"11":11.03,"12":15.15,"13":19.28,"14":23.41,"15":26.45,"16":27.36,"17":27.36,"18":27.36,"19":27.36}}]};
// Normalize month format "YYYY-M" → "YYYY-MM" in historical data
if (HISTORICAL_ROI_DATA?.monthly_results) {
HISTORICAL_ROI_DATA.monthly_results.forEach(m => {
const [y, mo] = m.month.split('-');
m.month = `${y}-${mo.padStart(2, '0')}`;
});
}
// Derive default purchaseDate from first month of historical data
const HISTORICAL_FIRST_DATE = HISTORICAL_ROI_DATA?.monthly_results?.[0]?.month
? HISTORICAL_ROI_DATA.monthly_results[0].month + '-01'
: '2024-10-01';
function predictSolarFromWeather(weatherDay, historicalAvgSolar) {
const cloudCover = weatherDay.day.avgvis_km < 5 ? 90 : weatherDay.day.daily_will_it_rain ? 70 : weatherDay.hour[12].cloud || 30;
const uvIndex = weatherDay.day.uv || 5;
const multiplier = WEATHER_SOLAR_CORRELATION.getSolarMultiplier(cloudCover, uvIndex);
// Get seasonal adjustment based on month
const date = new Date(weatherDay.date);
const month = date.getMonth(); // 0-11
const seasonalMultipliers = [1.2, 1.1, 0.9, 0.7, 0.5, 0.4, 0.45, 0.6, 0.8, 1.0, 1.1, 1.2]; // Jan-Dec
const seasonalAdj = seasonalMultipliers[month];
return historicalAvgSolar * multiplier * seasonalAdj;
}
// Predict battery performance based on predicted solar
function predictBatteryPerformance(predictedSolarKwh, batteryCapacityKwh = 32, chargeRateKw = 8, efficiencyPct = 97.5) {
// Simple model: assume linear charging from 0 to predicted solar over daylight hours
const efficiency = efficiencyPct / 100;
// Estimate charging hours (approximate)
const chargingHours = Math.min(predictedSolarKwh / (chargeRateKw * efficiency), 8);
const maxSOC = Math.min(predictedSolarKwh * efficiency, batteryCapacityKwh);
const fillPct = (maxSOC / batteryCapacityKwh) * 100;
// Estimate time to full (if possible)
let timeToFull = null;
if (fillPct >= 95) {
// Assume charging starts at 8am and reaches 95% at:
const hoursTo95 = (batteryCapacityKwh * 0.95) / (chargeRateKw * efficiency);
const hour = 8 + Math.min(hoursTo95, 8);
timeToFull = `${Math.floor(hour)}:${Math.floor((hour % 1) * 60).toString().padStart(2, '0')}`;
}
return {
predictedSolarKwh: Math.round(predictedSolarKwh * 10) / 10,
maxSOC: Math.round(maxSOC * 10) / 10,
fillPct: Math.round(fillPct * 10) / 10,
timeToFull,
performance: fillPct >= 95 ? 'Excellent' : fillPct >= 75 ? 'Good' : fillPct >= 50 ? 'Fair' : 'Poor'
};
}
/* ═══════════════════════════════════════════════════════════════════════
OPEN-METEO WEATHER FORECAST CONFIGURATION
16-day forecast with solar radiation data
═══════════════════════════════════════════════════════════════════════ */
// WMO Weather Code to condition label + icon mapping
const WMO_CODE_TO_CONDITION = {
0: { label: 'Clear sky', icon: '\u2600\uFE0F' },
1: { label: 'Mainly clear', icon: '\uD83C\uDF24\uFE0F' },
2: { label: 'Partly cloudy', icon: '\u26C5' },
3: { label: 'Overcast', icon: '\u2601\uFE0F' },
45: { label: 'Fog', icon: '\uD83C\uDF2B\uFE0F' },
48: { label: 'Rime fog', icon: '\uD83C\uDF2B\uFE0F' },
51: { label: 'Light drizzle', icon: '\uD83C\uDF26\uFE0F' },
53: { label: 'Moderate drizzle', icon: '\uD83C\uDF26\uFE0F' },
55: { label: 'Dense drizzle', icon: '\uD83C\uDF27\uFE0F' },
56: { label: 'Freezing drizzle', icon: '\uD83C\uDF28\uFE0F' },
57: { label: 'Heavy freezing drizzle', icon: '\uD83C\uDF28\uFE0F' },
61: { label: 'Slight rain', icon: '\uD83C\uDF26\uFE0F' },
63: { label: 'Moderate rain', icon: '\uD83C\uDF27\uFE0F' },
65: { label: 'Heavy rain', icon: '\uD83C\uDF27\uFE0F' },
66: { label: 'Light freezing rain', icon: '\uD83C\uDF28\uFE0F' },
67: { label: 'Heavy freezing rain', icon: '\uD83C\uDF28\uFE0F' },
71: { label: 'Slight snow', icon: '\uD83C\uDF28\uFE0F' },
73: { label: 'Moderate snow', icon: '\uD83C\uDF28\uFE0F' },
75: { label: 'Heavy snow', icon: '\uD83C\uDF28\uFE0F' },
77: { label: 'Snow grains', icon: '\uD83C\uDF28\uFE0F' },
80: { label: 'Slight showers', icon: '\uD83C\uDF26\uFE0F' },
81: { label: 'Moderate showers', icon: '\uD83C\uDF27\uFE0F' },
82: { label: 'Violent showers', icon: '\uD83C\uDF27\uFE0F' },
85: { label: 'Snow showers', icon: '\uD83C\uDF28\uFE0F' },
86: { label: 'Heavy snow showers', icon: '\uD83C\uDF28\uFE0F' },
95: { label: 'Thunderstorm', icon: '\u26C8\uFE0F' },
96: { label: 'T-storm + hail', icon: '\u26C8\uFE0F' },
99: { label: 'T-storm + heavy hail', icon: '\u26C8\uFE0F' },
};
// Monthly clear-sky solar radiation benchmarks for Adelaide (MJ/m2/day)
// Source: BOM solar exposure data for Adelaide Airport
const ADELAIDE_CLEAR_SKY_MJ = [28.5, 25.5, 20.5, 14.5, 10.0, 8.0, 9.0, 12.5, 17.5, 22.5, 26.5, 29.0];
// Monthly peak sun hours for Adelaide (equivalent to kWh/m2/day for a 1kW system)
const ADELAIDE_PEAK_SUN_HOURS = [7.2, 6.4, 5.1, 3.6, 2.5, 2.0, 2.2, 3.1, 4.4, 5.6, 6.6, 7.3];
// Convert Open-Meteo radiation (MJ/m2/day) to predicted solar kWh
function radiationToSolarKwh(radiationMJ, month, systemCapacityKw) {
if (!radiationMJ || radiationMJ <= 0) return 0;
const clearSkyMJ = ADELAIDE_CLEAR_SKY_MJ[month] || 18;
// Ratio of actual radiation to clear-sky benchmark
const solarRatio = Math.min(radiationMJ / clearSkyMJ, 1.2);
// Peak sun hours adjusted by actual conditions
const peakHours = ADELAIDE_PEAK_SUN_HOURS[month] * solarRatio;
// System output = capacity * peak hours * system losses (0.82 typical: inverter, wiring, temp, soiling)
return Math.round(systemCapacityKw * peakHours * 0.82 * 10) / 10;
}
// Transform raw Open-Meteo forecast into prediction objects
function processOpenMeteoForecast(forecastDays, cfg) {
if (!forecastDays || !forecastDays.length) return [];
const bCap = cfg.usableCapacity || 32;
const chargeRate = cfg.chargeRate || 8;
const efficiency = cfg.inverterEfficiency || 97.5;
const sysKw = cfg.solarCapacity || 5;
return forecastDays.map(day => {
const dateObj = new Date(day.date + 'T00:00:00');
const month = dateObj.getMonth();
const wmoInfo = WMO_CODE_TO_CONDITION[day.weather_code] || { label: 'Unknown', icon: '\uD83C\uDF24\uFE0F' };
const predictedSolarKwh = radiationToSolarKwh(day.shortwave_radiation_sum, month, sysKw);
const batteryPred = predictBatteryPerformance(predictedSolarKwh, bCap, chargeRate, efficiency);
return {
date: day.date,
dateObj,
dayName: dateObj.toLocaleDateString('en-AU', { weekday: 'short' }),
condition: wmoInfo.label,
conditionIcon: wmoInfo.icon,
weatherCode: day.weather_code,
tempMax: day.temp_max,
tempMin: day.temp_min,
cloudCover: day.cloud_cover_mean,
precipChance: day.precipitation_probability,
radiationMJ: day.shortwave_radiation_sum,
sunshineHours: day.sunshine_duration_hours,
...batteryPred,
};
});
}
function makeRateSet(from, label, overrides = {}) {
return {
id: Date.now() + Math.random(),
from, label,
sponge: 0.2701, peak: 0.5658, offPk: 0.3882,
feedIn: 0.055, supply: 1.2626, disc: 9, gst: 10,
...overrides,
};
}
function calcBill(d, r) {
const en = d.sponge * r.sponge + d.peak * r.peak + d.offPk * r.offPk;
const fi = d.feedIn * r.feedIn;
const su = d.days * r.supply;
const enD = en * (r.disc / 100);
const suD = su * (r.disc / 100);
const taxable = (en - enD) + (su - suD);
const gst = taxable * (r.gst / 100);
return { en, fi, su, enD, suD, taxable, gst, total: taxable - fi + gst, spongeC: d.sponge * r.sponge, peakC: d.peak * r.peak, offPkC: d.offPk * r.offPk };
}
function calcPmt(p, ar, ty) {
if (p <= 0) return 0;
const n = ty * 12, r = ar / 100 / 12;
if (ar === 0) return p / n;
return p * (r * Math.pow(1 + r, n)) / (Math.pow(1 + r, n) - 1);
}
/* ── Amortisation Schedule Generator ── */
function generateAmortSchedule(principal, annualRate, termYears, extraMonthly = 0) {
if (principal <= 0 || termYears <= 0) return [];
const n = termYears * 12;
const r = annualRate / 100 / 12;
const basePmt = annualRate === 0 ? principal / n : principal * (r * Math.pow(1 + r, n)) / (Math.pow(1 + r, n) - 1);
let balance = principal;
let cumInterest = 0;
let cumPrincipal = 0;
const schedule = [];
for (let i = 1; i <= n && balance > 0.01; i++) {
const interest = balance * r;
const totalPmt = Math.min(basePmt + extraMonthly, balance + interest);
const principalPortion = totalPmt - interest;
balance = Math.max(0, balance - principalPortion);
cumInterest += interest;
cumPrincipal += principalPortion;
schedule.push({
month: i,
payment: Math.round(totalPmt * 100) / 100,
principal: Math.round(principalPortion * 100) / 100,
interest: Math.round(interest * 100) / 100,
balance: Math.round(balance * 100) / 100,
cumInterest: Math.round(cumInterest * 100) / 100,
cumPrincipal: Math.round(cumPrincipal * 100) / 100,
});
if (balance <= 0.01) break;
}
return schedule;
}
/* ── Accelerated Repayment Calculator (battery savings applied as extra repayments) ── */
function generateAcceleratedSchedule(principal, annualRate, termYears, monthlySavings) {
if (principal <= 0 || termYears <= 0 || monthlySavings <= 0) return { schedule: [], standardSchedule: [], summary: null };
const standardSchedule = generateAmortSchedule(principal, annualRate, termYears, 0);
const acceleratedSchedule = generateAmortSchedule(principal, annualRate, termYears, monthlySavings);
const standardTotalInterest = standardSchedule.length > 0 ? standardSchedule[standardSchedule.length - 1].cumInterest : 0;
const accelTotalInterest = acceleratedSchedule.length > 0 ? acceleratedSchedule[acceleratedSchedule.length - 1].cumInterest : 0;
const monthsSaved = standardSchedule.length - acceleratedSchedule.length;
return {
schedule: acceleratedSchedule,
standardSchedule,
summary: {
originalMonths: standardSchedule.length,
acceleratedMonths: acceleratedSchedule.length,
monthsSaved,
yearsSaved: Math.round(monthsSaved / 12 * 10) / 10,
totalInterestStandard: Math.round(standardTotalInterest * 100) / 100,
totalInterestAccelerated: Math.round(accelTotalInterest * 100) / 100,
interestSaved: Math.round((standardTotalInterest - accelTotalInterest) * 100) / 100,
}
};
}
/* ── Adelaide sunrise/sunset hours by month (0=Jan) for SOC curve generation ── */
const ADELAIDE_SUNRISE_HOUR = [6.1, 6.6, 7.0, 7.3, 7.1, 7.2, 7.1, 6.7, 6.1, 6.3, 5.9, 5.8];
const ADELAIDE_SUNSET_HOUR = [20.4, 20.0, 19.3, 18.3, 17.5, 17.2, 17.4, 17.9, 18.5, 19.1, 19.8, 20.4];
/* ── Derive synthetic hourly SOC array from daily total solar ── */
function deriveHourlySoc(totalSolarKwh, dateStr, cfg) {
const dateObj = new Date(dateStr + 'T00:00:00');
const month = dateObj.getMonth();
const sunrise = ADELAIDE_SUNRISE_HOUR[month];
const sunset = ADELAIDE_SUNSET_HOUR[month];
const batteryCapacity = cfg.usableCapacity || cfg.batteryCapacity || 32;
const efficiency = (cfg.inverterEfficiency || 97.5) / 100;
const soc = {};
let cumSoc = 0;
for (let h = 4; h <= 21; h++) {
if (h < sunrise || h > sunset) {
soc[String(h)] = Math.round(cumSoc * 100) / 100;
continue;
}
// Sine-curve distribution: peak generation at solar noon
const solarNoon = (sunrise + sunset) / 2;
const halfWindow = (sunset - sunrise) / 2;
const angle = ((h - solarNoon) / halfWindow) * (Math.PI / 2);
const weight = Math.max(0, Math.cos(angle));
// Distribute total solar across daylight hours proportionally
const totalWeight = Array.from({length: Math.ceil(sunset - sunrise)}, (_, i) => {
const hr = Math.floor(sunrise) + i;
const a = ((hr - solarNoon) / halfWindow) * (Math.PI / 2);
return Math.max(0, Math.cos(a));
}).reduce((s, w) => s + w, 0);
const hourKwh = totalWeight > 0 ? (totalSolarKwh * weight / totalWeight) : 0;
cumSoc = Math.min(cumSoc + hourKwh * efficiency, batteryCapacity);
soc[String(h)] = Math.round(cumSoc * 100) / 100;
}
return soc;
}
/* ── Transform live DB data to historicalData shape ── */
function transformLiveToHistorical(liveDaily, liveMonthly, cfg) {
const dailyResults = liveDaily
.filter(d => d.total_yield_kwh > 0)
.map(d => {
const dateStr = d.date;
const solarKwh = d.total_yield_kwh || 0;
const bCap = cfg.usableCapacity || cfg.batteryCapacity || 32;
const chargeRate = cfg.chargeRate || 8;
const eff = (cfg.inverterEfficiency || 97.5) / 100;
const maxSoc = Math.min(solarKwh * eff, bCap);
const fillPct = (maxSoc / bCap) * 100;
let timeToFull = null;
if (fillPct >= 95) {
const hoursTo95 = (bCap * 0.95) / (chargeRate * eff);
const hour = 8 + Math.min(hoursTo95, 8);
timeToFull = `${Math.floor(hour)}:${Math.floor((hour % 1) * 60).toString().padStart(2, '0')}`;
}
const dateObj = new Date(dateStr + 'T00:00:00');
const dayNames = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'];
return {
date: dateStr,
day_of_week: dayNames[dateObj.getDay()],
total_solar_kwh: Math.round(solarKwh * 100) / 100,
max_battery_soc_kwh: Math.round(maxSoc * 100) / 100,
battery_filled_pct: Math.round(fillPct * 10) / 10,
time_to_full: timeToFull,
hourly_soc: deriveHourlySoc(solarKwh, dateStr, cfg)
};
});
// Monthly: compute cost estimates from solar generation
const buyRate = cfg.buyRate || 0.35;
const sellRate = cfg.sellRate || 0.07;
const dailySupply = cfg.dailySupply || 1.17;
const dailyUsage = cfg.dailyUsage || 20;
const monthlyResults = liveMonthly.map(m => {
const daysInMonth = m.days_with_data || 30;
const solarTotal = m.total_yield_kwh || 0;
const bCap = cfg.usableCapacity || cfg.batteryCapacity || 32;
// Estimate monthly consumption
const consumption = dailyUsage * daysInMonth;
// Cost without battery: all from grid
const costNoBattery = (consumption * buyRate) + (dailySupply * daysInMonth);
// With battery: self-consume up to battery capacity per day, export rest
const avgDailySolar = solarTotal / Math.max(daysInMonth, 1);
const dailySelfConsume = Math.min(avgDailySolar, Math.min(dailyUsage, bCap));
const dailyExport = Math.max(0, avgDailySolar - dailySelfConsume);
const dailyGridImport = Math.max(0, dailyUsage - dailySelfConsume);
const costWithBattery = (dailyGridImport * daysInMonth * buyRate) + (dailySupply * daysInMonth) - (dailyExport * daysInMonth * sellRate);
return {
month: m.month,
solar_total: Math.round(solarTotal * 100) / 100,
consumption: Math.round(consumption * 100) / 100,
cost_no_battery: Math.round(costNoBattery * 100) / 100,
cost_with_battery: Math.round(costWithBattery * 100) / 100,
savings: Math.round((costNoBattery - costWithBattery) * 100) / 100,
savings_with_sharer: Math.round((costNoBattery - costWithBattery) * 100) / 100
};
});
return { daily_results: dailyResults, monthly_results: monthlyResults };
}
/* ── Merge embedded historical data with live DB data ── */
function mergeHistoricalData(embedded, live) {
if (!live || (!live.daily_results.length && !live.monthly_results.length)) return embedded;
if (!embedded) return {
battery_spec: { capacity_kwh: 33.28, usable_kwh: 32, cost: 10700, rebate: 1500, net_cost: 9200 },
...live,
annual_no_sharer: { cost_no_battery: 0, cost_with_battery: 0, savings: 0, payback_years: 0 },
annual_with_sharer: { cost_no_battery: 0, cost_with_battery: 0, savings: 0, payback_years: 0 },
daily_charging: { total_days: 0, days_full: 0, pct_days_full: 0 }
};
// Merge daily_results — deduplicate by date, live wins on conflict
const dailyMap = new Map();
(embedded.daily_results || []).forEach(d => dailyMap.set(d.date, d));
(live.daily_results || []).forEach(d => dailyMap.set(d.date, d));
const mergedDaily = Array.from(dailyMap.values()).sort((a, b) => a.date.localeCompare(b.date));
// Merge monthly_results — deduplicate by month, live wins on conflict
const monthlyMap = new Map();
(embedded.monthly_results || []).forEach(m => monthlyMap.set(m.month, m));
(live.monthly_results || []).forEach(m => monthlyMap.set(m.month, m));
const mergedMonthly = Array.from(monthlyMap.values()).sort((a, b) => a.month.localeCompare(b.month));
// Recompute annual summaries from merged monthly data
const totalCostNoBattery = mergedMonthly.reduce((s, m) => s + (m.cost_no_battery || 0), 0);
const totalCostWithBattery = mergedMonthly.reduce((s, m) => s + (m.cost_with_battery || 0), 0);
const totalSavings = totalCostNoBattery - totalCostWithBattery;
const monthCount = mergedMonthly.length;
const annualFactor = monthCount > 0 ? 12 / monthCount : 1;
const annualSavings = totalSavings * annualFactor;
const netCost = embedded.battery_spec?.net_cost || 9200;
const paybackYears = annualSavings > 0 ? netCost / annualSavings : 99;
const annual = {
cost_no_battery: Math.round(totalCostNoBattery * annualFactor * 100) / 100,
cost_with_battery: Math.round(totalCostWithBattery * annualFactor * 100) / 100,
savings: Math.round(annualSavings * 100) / 100,
payback_years: Math.round(paybackYears * 100) / 100
};
// Recompute daily_charging from merged daily data
const daysFull = mergedDaily.filter(d => (d.battery_filled_pct || 0) >= 95).length;
const fullDays = mergedDaily.filter(d => d.time_to_full);
let avgTimeToFull = embedded.daily_charging?.avg_time_to_full || null;
if (fullDays.length > 0) {
const totalMinutes = fullDays.reduce((s, d) => {
const [h, m] = d.time_to_full.split(':').map(Number);
return s + h * 60 + m;
}, 0);
const avgMin = totalMinutes / fullDays.length;
avgTimeToFull = `${Math.floor(avgMin / 60)}:${Math.floor(avgMin % 60).toString().padStart(2, '0')}`;
}
// Merge hourly_soc averages for daily_charging
const hourlySocSums = {};
const hourlySocCounts = {};
mergedDaily.forEach(d => {
if (!d.hourly_soc) return;
Object.entries(d.hourly_soc).forEach(([h, val]) => {
hourlySocSums[h] = (hourlySocSums[h] || 0) + val;
hourlySocCounts[h] = (hourlySocCounts[h] || 0) + 1;
});
});
const avgHourlySoc = {};
Object.keys(hourlySocSums).sort((a, b) => Number(a) - Number(b)).forEach(h => {
avgHourlySoc[h] = Math.round((hourlySocSums[h] / hourlySocCounts[h]) * 100) / 100;
});
return {
battery_spec: embedded.battery_spec,
annual_no_sharer: annual,
annual_with_sharer: annual,
monthly_results: mergedMonthly,
daily_results: mergedDaily,
daily_charging: {
total_days: mergedDaily.length,
days_full: daysFull,
pct_days_full: mergedDaily.length > 0 ? Math.round((daysFull / mergedDaily.length) * 1000) / 10 : 0,
avg_time_to_full: avgTimeToFull,
earliest_full: embedded.daily_charging?.earliest_full || null,
latest_full: embedded.daily_charging?.latest_full || null,
hourly_soc: avgHourlySoc,
seasons: embedded.daily_charging?.seasons || {}
}
};
}
/* ── Fresh Battery Baseline — models 100% capacity from day 1 ── */
/* Daily results have: date, total_solar_kwh, max_battery_soc_kwh, battery_filled_pct, time_to_full */
/* We estimate daily savings from battery fill % and solar, since daily_saving isn't in the data */
function computeIdealBaseline(dailyResults, usableCapacity, monthlyData) {
if (!dailyResults || dailyResults.length === 0) return null;
// Estimate avg daily saving from monthly totals
let avgDailySaving = 3.5; // fallback $3.50/day
if (monthlyData && monthlyData.length > 0) {
const totalMonthlySavings = monthlyData.reduce((s, m) => s + (m.savings || 0), 0);
const totalDays = monthlyData.length * 30; // approx
avgDailySaving = totalMonthlySavings / totalDays;
}
// For each day, estimate savings proportional to battery fill
// Full days = max savings, partial days = proportional
const idealData = [];
let cumActual = 0;
let cumIdeal = 0;
dailyResults.forEach((day, i) => {
const filledPct = Math.min((day.battery_filled_pct || 0) / 100, 1.0);
const solarKwh = day.total_solar_kwh || 0;
// Actual savings scaled by how full the battery got
const actualSaving = avgDailySaving * filledPct * (solarKwh > 5 ? 1.0 : 0.5);
// Ideal savings: assume battery always reaches 100% if solar > threshold
const idealFill = solarKwh >= usableCapacity * 0.8 ? 1.0 : Math.min(solarKwh / (usableCapacity * 0.8), 1.0);
const idealSaving = avgDailySaving * idealFill * (solarKwh > 2 ? 1.0 : 0.3);
cumActual += actualSaving;
cumIdeal += idealSaving;
idealData.push({
date: day.date,
dayIndex: i + 1,
actualSaving: Math.round(actualSaving * 100) / 100,
idealSaving: Math.round(idealSaving * 100) / 100,
cumActual: Math.round(cumActual * 100) / 100,
cumIdeal: Math.round(cumIdeal * 100) / 100,
delta: Math.round((cumIdeal - cumActual) * 100) / 100,
});
});
return {
data: idealData,
totalActual: Math.round(cumActual * 100) / 100,
totalIdeal: Math.round(cumIdeal * 100) / 100,
moneyLeftOnTable: Math.round((cumIdeal - cumActual) * 100) / 100,
};
}
/* ── Lifetime Cost Comparison Data (4 scenarios over N years) ── */
function generateLifetimeCostData(annualBillNoBattery, annualSavingsBase, netCost, escalation, financeRate, financeTerm, years) {
const data = [];
let cumNoBattery = 0;
let cumUpfront = netCost; // upfront starts with initial cost paid
let cumFinanced = 0;
let cumAccelerated = 0;
const monthlyPmt = calcPmt(netCost, financeRate, financeTerm);
// For accelerated: estimate monthly savings from year 1 data
const avgMonthlySavings = annualSavingsBase / 12;
const accelResult = generateAcceleratedSchedule(netCost, financeRate, financeTerm, avgMonthlySavings);
const accelMonths = accelResult.summary ? accelResult.summary.acceleratedMonths : financeTerm * 12;
for (let yr = 1; yr <= years; yr++) {
const esc = Math.pow(1 + escalation / 100, yr);
const yearBillNoBatt = annualBillNoBattery * esc;
const yearSavings = annualSavingsBase * esc;
const yearBillWithBatt = yearBillNoBatt - yearSavings;
cumNoBattery += yearBillNoBatt;
// Upfront: just energy costs (already paid the battery)
cumUpfront += yearBillWithBatt;
// Financed: energy + monthly payments during loan term
const finPayments = yr <= financeTerm ? monthlyPmt * 12 : 0;
cumFinanced += yearBillWithBatt + finPayments;
// Accelerated: energy + (base payment + savings) during shortened term
const accelYrs = Math.ceil(accelMonths / 12);
if (yr <= accelYrs) {
// During accelerated repayment: energy savings redirected to loan, so total outflow = full bill + payments
cumAccelerated += yearBillNoBatt + (monthlyPmt * 12);
} else {
// After payoff: same as upfront (just energy with battery savings)
cumAccelerated += yearBillWithBatt;
}
data.push({
year: yr,
label: `Year ${yr}`,
'No Battery': Math.round(cumNoBattery),
'Battery (Upfront)': Math.round(cumUpfront),
'Battery (Financed)': Math.round(cumFinanced),
'Battery (Accelerated)': Math.round(cumAccelerated),
});
}
return data;
}
/* ── Styles ── */
const S = {
page: { background: "linear-gradient(145deg,var(--bg-page) 0%,var(--bg-page-end) 50%,var(--bg-page-mid) 100%)", color: "var(--text)", minHeight: "100vh", fontFamily: "'Segoe UI',system-ui,sans-serif" },
hdr: { background: "linear-gradient(90deg,rgba(245,158,11,0.12),rgba(16,185,129,0.08))", borderBottom: "1px solid var(--border)", padding: "20px clamp(12px, 2vw, 24px) 16px" },
h1: { fontSize: "24px", fontWeight: 700, margin: "0 0 2px", background: "linear-gradient(90deg,#fbbf24,#34d399)", WebkitBackgroundClip: "text", WebkitTextFillColor: "transparent" },
sub: { fontSize: "13px", color: "var(--text-muted)", margin: 0 },
tabs: { display: "flex", borderBottom: "1px solid var(--border)", background: "var(--bg-header)", overflowX: "auto" },
tab: a => ({ flex: "1 0 auto", padding: "12px 14px", border: "none", cursor: "pointer", fontSize: "13px", fontWeight: a ? 600 : 400, color: a ? "#fbbf24" : "var(--text-muted)", background: a ? "rgba(245,158,11,0.06)" : "transparent", borderBottom: a ? "2px solid #fbbf24" : "2px solid transparent", whiteSpace: "nowrap" }),
body: { padding: "20px clamp(12px, 2vw, 24px) 40px" },
card: { background: "var(--bg-card)", border: "1px solid var(--border)", borderRadius: "10px", padding: "16px", marginBottom: "14px" },
cT: { fontSize: "13px", fontWeight: 600, color: "#fbbf24", marginBottom: "12px", textTransform: "uppercase", letterSpacing: "0.5px" },
lbl: { fontSize: "12px", color: "var(--text-muted)", marginBottom: "3px", display: "block" },
inp: { width: "100%", padding: "8px 10px", background: "var(--bg-input)", border: "1px solid var(--border-light)", borderRadius: "6px", color: "var(--text)", fontSize: "13px", outline: "none", boxSizing: "border-box" },
inpSm: { width: "100%", padding: "8px 10px", background: "var(--bg-input)", border: "1px solid var(--border-light)", borderRadius: "5px", color: "var(--text)", fontSize: "12px", outline: "none", textAlign: "right", boxSizing: "border-box" },
btn: p => ({ padding: "8px 18px", border: "none", borderRadius: "6px", cursor: "pointer", fontSize: "12px", fontWeight: 600, color: p ? "var(--bg-input)" : "var(--text-secondary)", background: p ? "linear-gradient(135deg,#fbbf24,#f59e0b)" : "rgba(51,65,85,0.5)", whiteSpace: "nowrap" }),
btnSm: (p, c) => ({ padding: "5px 10px", border: `1px solid ${p ? (c || "#fbbf24") : "var(--border-light)"}`, borderRadius: "5px", cursor: "pointer", fontSize: "11px", fontWeight: p ? 600 : 400, color: p ? (c || "#fbbf24") : "var(--text-muted)", background: p ? (c || "#fbbf24") + "15" : "transparent" }),
tgl: a => ({ padding: "7px 14px", border: `1px solid ${a ? "#fbbf24" : "var(--border-light)"}`, borderRadius: "5px", cursor: "pointer", fontSize: "12px", fontWeight: a ? 600 : 400, color: a ? "#fbbf24" : "var(--text-muted)", background: a ? "rgba(245,158,11,0.1)" : "transparent" }),
th: { padding: "10px 10px", textAlign: "right", color: "var(--text-muted)", fontWeight: 600, borderBottom: "1px solid var(--border)", fontSize: "11px", textTransform: "uppercase", letterSpacing: "0.3px" },
td: { padding: "7px 10px", borderBottom: "1px solid var(--border)" },
stat: c => ({ background: "var(--bg-card)", border: `1px solid ${c}30`, borderRadius: "10px", padding: "14px 16px", flex: "1 1 130px", minWidth: "130px" }),
sL: { fontSize: "11px", color: "var(--text-muted)", marginBottom: "3px", textTransform: "uppercase", letterSpacing: "0.4px" },
sV: c => ({ fontSize: "22px", fontWeight: 700, color: c, margin: 0, lineHeight: 1.2 }),
sS: { fontSize: "11px", color: "var(--text-dim)", marginTop: "2px" },
badge: c => ({ display: "inline-block", padding: "2px 7px", borderRadius: "4px", fontSize: "11px", fontWeight: 600, color: c, background: c + "15" }),
slider: { width: "100%", accentColor: "#f59e0b", cursor: "pointer" },
rateCard: (active) => ({ background: active ? "rgba(245,158,11,0.06)" : "var(--bg-input)", border: `1px solid ${active ? "#fbbf2440" : "var(--border)"}`, borderRadius: "8px", padding: "14px", marginBottom: "10px" }),
dot: c => ({ width: 8, height: 8, borderRadius: "50%", background: c, display: "inline-block", marginRight: 6, flexShrink: 0 }),
};
const RATE_COLORS = ["#fbbf24", "#38bdf8", "#a78bfa", "#f87171", "#34d399", "#fb923c"];
const TT = ({ active, payload, label }) => {
if (!active || !payload?.length) return null;
return (
<div style={{ background: "var(--border)", border: "1px solid var(--border-light)", borderRadius: "8px", padding: "10px 14px", fontSize: "12px" }}>
<div style={{ fontWeight: 600, marginBottom: 6, color: "var(--text)" }}>{label}</div>
{payload.map((p, i) => <div key={i} style={{ display: "flex", alignItems: "center", gap: 6, marginBottom: 2 }}>
<div style={{ width: 8, height: 8, borderRadius: 2, background: p.color, flexShrink: 0 }} />
<span style={{ color: "var(--text-secondary)" }}>{p.name}:</span>
<span style={{ color: "var(--text)", fontWeight: 500 }}>{fmt(p.value)}</span>
</div>)}
</div>
);
};
/* ── LocalStorage persistence ── */
const STORAGE_KEY = "batteryROI_v2";
const loadSaved = () => { try { return JSON.parse(localStorage.getItem(STORAGE_KEY)); } catch { return null; } };
const saved = loadSaved() || {
rateSets: [
{ id: 1, from: "2024-10-01", label: "Rate period 1", sponge: 0.2349, peak: 0.4920, offPk: 0.3376, feedIn: 0.055, supply: 1.0979, disc: 9, gst: 10 },
{ id: 2, from: "2025-07-01", label: "Rate period 2", sponge: 0.2701, peak: 0.5658, offPk: 0.3882, feedIn: 0.055, supply: 1.2626, disc: 9, gst: 10 },
],
entries: [
{ id: 101, billFrom: "2024-10-10", days: "31", sponge: "6.77", peak: "194.67", offPk: "55.93", feedIn: "601.14", month: 9, year: 2024 },
{ id: 102, billFrom: "2024-11-10", days: "30", sponge: "15.61", peak: "239.23", offPk: "44.44", feedIn: "585.95", month: 10, year: 2024 },
{ id: 103, billFrom: "2024-12-10", days: "31", sponge: "20.08", peak: "276.29", offPk: "57.89", feedIn: "595.11", month: 11, year: 2024 },
{ id: 104, billFrom: "2025-01-10", days: "31", sponge: "9.34", peak: "368.69", offPk: "57.70", feedIn: "455.95", month: 0, year: 2025 },
{ id: 105, billFrom: "2025-02-10", days: "28", sponge: "15.72", peak: "319.99", offPk: "45.69", feedIn: "385.60", month: 1, year: 2025 },
{ id: 106, billFrom: "2025-03-10", days: "31", sponge: "16.04", peak: "329.14", offPk: "63.56", feedIn: "389.52", month: 2, year: 2025 },
{ id: 107, billFrom: "2025-04-10", days: "30", sponge: "22.34", peak: "301.30", offPk: "82.25", feedIn: "245.71", month: 3, year: 2025 },
{ id: 108, billFrom: "2025-05-10", days: "31", sponge: "37.88", peak: "564.18", offPk: "236.40", feedIn: "204.65", month: 4, year: 2025 },
{ id: 109, billFrom: "2025-06-10", days: "21", sponge: "13.83", peak: "431.13", offPk: "171.43", feedIn: "161.51", month: 5, year: 2025 },
{ id: 110, billFrom: "2025-06-30", days: "9", sponge: "7.54", peak: "191.69", offPk: "79.21", feedIn: "0", month: 5, year: 2025 },
{ id: 111, billFrom: "2025-07-10", days: "31", sponge: "28.75", peak: "657.57", offPk: "269.27", feedIn: "218.55", month: 6, year: 2025 },
{ id: 112, billFrom: "2025-08-10", days: "31", sponge: "18.20", peak: "529.54", offPk: "241.35", feedIn: "314.35", month: 7, year: 2025 },
{ id: 113, billFrom: "2025-09-10", days: "30", sponge: "5.30", peak: "375.96", offPk: "182.94", feedIn: "476.62", month: 8, year: 2025 },
{ id: 114, billFrom: "2025-10-10", days: "31", sponge: "12.86", peak: "315.36", offPk: "137.03", feedIn: "486.26", month: 9, year: 2025 },
{ id: 115, billFrom: "2025-11-10", days: "30", sponge: "10.11", peak: "329.87", offPk: "133.32", feedIn: "518.06", month: 10, year: 2025 },
{ id: 116, billFrom: "2025-12-10", days: "31", sponge: "7.12", peak: "475.09", offPk: "132.98", feedIn: "411.76", month: 11, year: 2025 },
],
cfg: {
batteryCost: 25282, repsRebate: 9782,
forecastYears: 10, escalation: 4,
payType: "finance", financeTerm: 6, financeRate: 6.99,
useAmber: true, amberFitAvg: 0.12, amberImportDisc: 0.25,
amberSpikeMult: 1.0, amberFee: 25, scenario: 1.0,
},
};
/* ══════════════════════════════════════════════════════════════
Battery ROI Calculator — Tab 1: Finance Calculator
══════════════════════════════════════════════════════════════ */
/* ═══════════════════════════════════════════════════════════════════════
FINANCE CALCULATOR - Flexible Lender Comparison
═══════════════════════════════════════════════════════════════════════ */
function calculateEffectiveAPR(principal, termYears, interestRate, feeAmount, feeFrequency, establishmentFee) {
// Convert fee frequency to annual payments
const frequencyMap = {
'weekly': 52,
'fortnightly': 26,
'monthly': 12,
'quarterly': 4,
'annually': 1
};
const paymentsPerYear = frequencyMap[feeFrequency] || 12;
const totalPayments = termYears * paymentsPerYear;
// Calculate payment per period
let paymentPerPeriod;
if (interestRate === 0 && feeAmount > 0) {
// Fee-based loan (like Brighte): principal/periods + flat fee
paymentPerPeriod = (principal / totalPayments) + feeAmount;
} else if (interestRate > 0 && feeAmount === 0) {
// Traditional interest-only loan: calculate using amortization formula
const r = (interestRate / 100) / paymentsPerYear;
paymentPerPeriod = principal * (r * Math.pow(1 + r, totalPayments)) / (Math.pow(1 + r, totalPayments) - 1);
} else if (interestRate > 0 && feeAmount > 0) {
// Hybrid: interest calculation + flat fee
const r = (interestRate / 100) / paymentsPerYear;
const interestPayment = principal * (r * Math.pow(1 + r, totalPayments)) / (Math.pow(1 + r, totalPayments) - 1);
paymentPerPeriod = interestPayment + feeAmount;
} else {
// No interest, no fees: just principal repayment
return 0;
}
// Use Newton's method to find the effective rate (IRR)
let r = 0.001 / paymentsPerYear; // initial guess
for (let iter = 0; iter < 200; iter++) {
let npv = 0;
let dnpv = 0;
for (let i = 1; i <= totalPayments; i++) {
const payment = i === 1 ? paymentPerPeriod + establishmentFee : paymentPerPeriod;
const discount = Math.pow(1 + r, i);
npv += payment / discount;
dnpv -= i * payment / (discount * (1 + r));
}
npv -= principal;
const newR = r - npv / dnpv;
if (Math.abs(newR - r) < 1e-12) {
r = newR;
break;
}
r = newR;
}
const annualRate = Math.pow(1 + r, paymentsPerYear) - 1;
return annualRate * 100;
}
function calculateTotalCost(principal, termYears, interestRate, feeAmount, feeFrequency, establishmentFee) {
const frequencyMap = { 'weekly': 52, 'fortnightly': 26, 'monthly': 12, 'quarterly': 4, 'annually': 1 };
const paymentsPerYear = frequencyMap[feeFrequency] || 12;
const totalPayments = termYears * paymentsPerYear;
let paymentPerPeriod;
let totalInterest = 0;
if (interestRate === 0 && feeAmount > 0) {
paymentPerPeriod = (principal / totalPayments) + feeAmount;
totalInterest = 0;
} else if (interestRate > 0 && feeAmount === 0) {
const r = (interestRate / 100) / paymentsPerYear;
paymentPerPeriod = principal * (r * Math.pow(1 + r, totalPayments)) / (Math.pow(1 + r, totalPayments) - 1);
totalInterest = (paymentPerPeriod * totalPayments) - principal;
} else if (interestRate > 0 && feeAmount > 0) {
const r = (interestRate / 100) / paymentsPerYear;
const interestPayment = principal * (r * Math.pow(1 + r, totalPayments)) / (Math.pow(1 + r, totalPayments) - 1);
paymentPerPeriod = interestPayment + feeAmount;
totalInterest = (interestPayment * totalPayments) - principal;
} else {
paymentPerPeriod = principal / totalPayments;
totalInterest = 0;
}