|
52 | 52 | // Number between 0 and 1 to indicate progress.
|
53 | 53 | let getting_data_error = null;
|
54 | 54 |
|
| 55 | + let fetched_logs = []; |
| 56 | +
|
55 | 57 | async function* getData(){
|
56 | 58 | getting_data_progress = null;
|
57 |
| - let response = await fetch(API_URL + '/data/meta.json'); |
| 59 | + let response = await fetch(API_URL + '/data/meta.csv'); |
58 | 60 | if (!response.ok){
|
59 | 61 | throw new Error(response.statusText);
|
60 | 62 | }
|
61 |
| - const meta = await response.json(); |
| 63 | + const meta = await response.text(); |
62 | 64 | let logs = processDataMeta(meta);
|
| 65 | + let original_log_file_count = logs.length; |
| 66 | +
|
| 67 | + // Skip data that doesn't have complete time information: |
| 68 | + logs = logs.filter(function(a){ |
| 69 | + return !(a.start_time_offset === null); |
| 70 | + }); |
| 71 | +
|
| 72 | + let valid_log_file_count = logs.length; |
| 73 | +
|
| 74 | + // Skip data that we already have: |
| 75 | + logs = logs.filter(function(a){ |
| 76 | + return !fetched_logs.some(function(b){ |
| 77 | + return b.active == false && a.number == b.number && a.start_time_offset == b.start_time_offset && a.start_time == b.start_time; |
| 78 | + }) |
| 79 | + }); |
| 80 | + console.log(`Number of log files: total: ${original_log_file_count} valid: ${valid_log_file_count} new: ${logs.length}`); |
63 | 81 |
|
64 | 82 | // Load the newest data first as that's most likely to be viewed first:
|
65 | 83 | logs.sort(function(a, b) {
|
|
82 | 100 | if (new_progress > getting_data_progress){
|
83 | 101 | getting_data_progress = Math.round(new_progress * 100) / 100;
|
84 | 102 | // Rounding seems to fix a really weird problem where ther progress bar jumps
|
85 |
| - // around slightly when during chart updates. It also smoothes things out a |
| 103 | + // around slightly when doing chart updates. It also smoothes things out a |
86 | 104 | // bit and makes it look better overall.
|
87 | 105 | }
|
88 | 106 | });
|
89 | 107 |
|
| 108 | + // Seeing if we have downloaded part of this log file before and getting the time where we left off: |
| 109 | + let previous_logs = fetched_logs.filter(function(a){ |
| 110 | + return a.active && a.number == log.number && a.start_time == log.start_time && a.start_time_offset == log.start_time_offset; |
| 111 | + }); |
| 112 | + let last_processed_time = null; |
| 113 | + if (previous_logs.length > 0){ |
| 114 | + let previous_log = previous_logs[previous_logs.length-1]; |
| 115 | + last_processed_time = previous_log.last_processed_time; |
| 116 | + } |
| 117 | +
|
90 | 118 | // const response_text = await response.text();
|
91 |
| - yield await processLogResponse(response_text, log.start_time_offset); |
| 119 | + let data = await processLogResponse(response_text, log.start_time_offset, last_processed_time); |
| 120 | + if (data.length > 0){ |
| 121 | + log.last_processed_time = data[data.length-1][0]; |
| 122 | + fetched_logs.push(log); |
| 123 | + } |
| 124 | + console.log(`New Data points from ${log.number} since ${last_processed_time}: ${data.length}`); |
| 125 | + yield data; |
| 126 | + } |
| 127 | + } |
| 128 | +
|
| 129 | + let historical_fetcher = null; |
| 130 | + let historical_fetcher_setup = false; |
| 131 | + let pull_historical_data_period_seconds = 300; |
| 132 | +
|
| 133 | + function setup_historical_fetcher(){ |
| 134 | + if (historical_fetcher_setup === false){ |
| 135 | + historical_fetcher_setup = true; |
| 136 | + document.addEventListener("visibilitychange", function (){ |
| 137 | + if (historical_fetcher != null){ |
| 138 | + clearInterval(historical_fetcher); |
| 139 | + historical_fetcher = null; |
| 140 | + } |
| 141 | + if (!document.hidden){ |
| 142 | + setup_historical_fetcher(); |
| 143 | + } |
| 144 | + }, false); |
92 | 145 | }
|
| 146 | +
|
| 147 | + get_historical_data(); |
| 148 | + historical_fetcher = setInterval(function() { |
| 149 | + get_historical_data(); |
| 150 | + }, pull_historical_data_period_seconds * 1000); |
93 | 151 | }
|
94 | 152 |
|
| 153 | + let getting_data = false; |
| 154 | +
|
95 | 155 | async function get_historical_data(){
|
| 156 | + if (getting_data){ |
| 157 | + console.log("Still getting data from last time."); |
| 158 | + return; |
| 159 | + } |
| 160 | + getting_data = true; |
96 | 161 | try{
|
97 | 162 | for await (const data of getData()) {
|
98 | 163 | historical_data = [...historical_data, ...data];
|
99 | 164 | }
|
| 165 | + getting_data_error = null; |
100 | 166 | } catch(e){
|
101 | 167 | getting_data_error = e.message;
|
102 | 168 | console.log(`Error getting data: ${getting_data_error}`);
|
103 | 169 | }
|
| 170 | + getting_data = false; |
104 | 171 | }
|
105 | 172 |
|
106 | 173 | let websocket = null;
|
107 | 174 | let websocket_retry_period = 1;
|
108 | 175 | let close_websocket_after_tab_changed_for_seconds = 50;
|
109 |
| - let visibilitychange_setup = false; |
110 |
| - let last_visibility_change_timeout = null; |
| 176 | + let websocket_visibilitychange_setup = false; |
| 177 | + let websocket_last_visibility_change_timeout = null; |
111 | 178 |
|
112 | 179 | function setup_realtime_websocket(){
|
113 |
| - if (visibilitychange_setup === false) { |
114 |
| - visibilitychange_setup = true; |
| 180 | + if (websocket_visibilitychange_setup === false) { |
| 181 | + websocket_visibilitychange_setup = true; |
115 | 182 | document.addEventListener("visibilitychange", function (){
|
116 |
| - if (last_visibility_change_timeout != null){ |
117 |
| - clearTimeout(last_visibility_change_timeout); |
118 |
| - last_visibility_change_timeout = null; |
| 183 | + if (websocket_last_visibility_change_timeout != null){ |
| 184 | + clearTimeout(websocket_last_visibility_change_timeout); |
| 185 | + websocket_last_visibility_change_timeout = null; |
119 | 186 | }
|
120 | 187 | if (document.hidden){
|
121 |
| - last_visibility_change_timeout = setTimeout(function() { |
| 188 | + websocket_last_visibility_change_timeout = setTimeout(function() { |
122 | 189 | if (websocket !== null){
|
123 | 190 | websocket.close();
|
124 | 191 | }
|
|
188 | 255 | }
|
189 | 256 | loading = false;
|
190 | 257 | get_stats();
|
191 |
| - get_historical_data(); |
| 258 | + setup_historical_fetcher(); |
192 | 259 | setup_realtime_websocket();
|
193 | 260 |
|
194 | 261 | }
|
|
202 | 269 | <FullPageProgress action={loading_action} action_verb={loading_verb} error={loading_error}/>
|
203 | 270 | {:else}
|
204 | 271 | <h1>Power Meter</h1>
|
| 272 | + |
205 | 273 | <div class="mdc-layout-grid">
|
206 | 274 | <div class="mdc-layout-grid__inner">
|
207 |
| - <div class="mdc-layout-grid__cell--span-6"> |
| 275 | + <div class="mdc-layout-grid__cell--span-12"> |
| 276 | + <PowerUsage progress={getting_data_progress} data={historical_data} error={getting_data_error} refresh_data={get_historical_data}/> |
| 277 | + </div> |
| 278 | + </div> |
| 279 | + </div> |
| 280 | + |
| 281 | + <div class="mdc-layout-grid"> |
| 282 | + <div class="mdc-layout-grid__inner"> |
| 283 | + <div class="mdc-layout-grid__cell--span-12"> |
208 | 284 | <Realtime websocket={websocket} title="Realtime" y_label="Power [W]"
|
209 | 285 | series={[
|
210 | 286 | {
|
|
224 | 300 | },
|
225 | 301 | ]}/>
|
226 | 302 | </div>
|
227 |
| - <div class="mdc-layout-grid__cell--span-6"> |
228 |
| - <PowerUsage progress={getting_data_progress} data={historical_data} error={getting_data_error}/> |
229 |
| - </div> |
230 | 303 | </div>
|
231 | 304 | </div>
|
| 305 | + |
232 | 306 | <div class="mdc-layout-grid">
|
233 | 307 | <div class="mdc-layout-grid__inner">
|
234 | 308 | <div class="mdc-layout-grid__cell--span-6">
|
|
0 commit comments