@@ -4,24 +4,35 @@ import { fetchBatteryHistory, recordBatteryCharge } from '../services/batteryHis
44/**
55 * Custom hook for fetching and managing battery history data
66 * @param {number|null } upsId - The ID of the UPS system to fetch history for
7+ * @param {number } timeFilter - Number of days to fetch history for (default: 7)
78 * @returns {Object } - Battery history data and loading state
89 */
9- export const useBatteryHistory = ( upsId ) => {
10+ export const useBatteryHistory = ( upsId , timeFilter = 7 ) => {
1011 const [ batteryHistory , setBatteryHistory ] = useState ( {
1112 labels : [ ] ,
1213 datasets : [ ] ,
1314 } ) ;
1415 const [ loading , setLoading ] = useState ( false ) ;
1516 const [ error , setError ] = useState ( null ) ;
17+ const [ currentTimeFilter , setCurrentTimeFilter ] = useState ( timeFilter ) ;
18+
19+ // Update the time filter when it changes
20+ useEffect ( ( ) => {
21+ setCurrentTimeFilter ( timeFilter ) ;
22+ } , [ timeFilter ] ) ;
1623
1724 // Function to fetch and process battery history data
18- const fetchAndProcessData = async ( ) => {
25+ const fetchAndProcessData = async ( days = currentTimeFilter ) => {
1926 try {
2027 setLoading ( true ) ;
2128 setError ( null ) ;
2229
30+ console . log ( `Fetching battery history for UPS ${ upsId } with time filter: ${ days } days` ) ;
31+
2332 // Use our service to fetch the data
24- const data = await fetchBatteryHistory ( upsId ) ;
33+ const data = await fetchBatteryHistory ( upsId , days ) ;
34+
35+ console . log ( `Received ${ data ?. length || 0 } data points for the last ${ days } days` ) ;
2536
2637 if ( ! data || data . length === 0 ) {
2738 console . log ( 'No battery history data available' ) ;
@@ -36,17 +47,81 @@ export const useBatteryHistory = (upsId) => {
3647
3748 // Process the data for the chart
3849 // The API returns an array of objects with charge_percent and timestamp
50+ console . log ( 'Raw data from API:' , data ) ;
51+
52+ // Sort the data by timestamp
3953 const sortedData = [ ...data ] . sort ( ( a , b ) => new Date ( a . timestamp ) - new Date ( b . timestamp ) ) ;
4054
55+ console . log ( `Sorted data: ${ sortedData . length } records` ) ;
56+
57+ // Even though the server should filter the data, we'll also filter it on the client side
58+ // to ensure we only show data for the requested time period
59+ const now = new Date ( ) ;
60+ const oldestAllowedDate = new Date ( now ) ;
61+ oldestAllowedDate . setDate ( oldestAllowedDate . getDate ( ) - days ) ;
62+ console . log ( `Client-side filtering: Only including records after ${ oldestAllowedDate . toLocaleString ( ) } ` ) ;
63+
64+ // Filter the data to only include records within the requested time period
65+ const filteredData = sortedData . filter ( item => {
66+ const timestamp = new Date ( item . timestamp ) ;
67+ return timestamp >= oldestAllowedDate ;
68+ } ) ;
69+
70+ console . log ( `After client-side filtering: ${ filteredData . length } records (was ${ sortedData . length } )` ) ;
71+
72+ // For multi-day views, ensure we get a good representation of the data across the full time range
73+ let finalData = filteredData ;
74+
75+ if ( days > 1 ) {
76+ console . log ( `Ensuring good data representation for ${ days } -day view` ) ;
77+
78+ // Calculate the time range we want to cover (from now to N days ago)
79+ const now = new Date ( ) ;
80+ const oldestAllowedDate = new Date ( now ) ;
81+ oldestAllowedDate . setDate ( oldestAllowedDate . getDate ( ) - days ) ;
82+
83+ // If we don't have data going back the full requested time range,
84+ // we'll work with what we have and distribute it evenly
85+
86+ // Calculate how many data points we want per day (aim for about 12)
87+ const totalDesiredPoints = days * 12 ;
88+
89+ if ( filteredData . length > totalDesiredPoints ) {
90+ // If we have more points than desired, sample them
91+ const samplingInterval = Math . max ( 1 , Math . floor ( filteredData . length / totalDesiredPoints ) ) ;
92+
93+ console . log ( `Sampling interval: ${ samplingInterval } (keeping 1 out of every ${ samplingInterval } points)` ) ;
94+
95+ // Sample the data at regular intervals
96+ finalData = filteredData . filter ( ( _ , index ) => index % samplingInterval === 0 ) ;
97+
98+ // Always include the first and last points to ensure we cover the full time range
99+ if ( finalData [ 0 ] !== filteredData [ 0 ] ) {
100+ finalData . unshift ( filteredData [ 0 ] ) ;
101+ }
102+ if ( finalData [ finalData . length - 1 ] !== filteredData [ filteredData . length - 1 ] ) {
103+ finalData . push ( filteredData [ filteredData . length - 1 ] ) ;
104+ }
105+
106+ console . log ( `After sampling: ${ finalData . length } records (was ${ filteredData . length } )` ) ;
107+ } else {
108+ // If we have fewer points than desired, use all of them
109+ console . log ( `Using all ${ filteredData . length } records (fewer than desired ${ totalDesiredPoints } )` ) ;
110+
111+ // If we have very few points, we might want to interpolate additional points
112+ // to get a smoother chart, but for now we'll just use what we have
113+ }
114+ }
115+
41116 // Check if the data has the expected properties
42117 let timestamps , charges ;
43118
44- if ( sortedData . length > 0 && ! sortedData [ 0 ] . charge_percent ) {
119+ if ( finalData . length > 0 && ! finalData [ 0 ] . charge_percent ) {
45120 console . warn ( 'Data format issue: charge_percent not found in data' ) ;
46- console . log ( 'Data sample:' , sortedData [ 0 ] ) ;
121+ console . log ( 'Data sample:' , finalData [ 0 ] ) ;
47122
48123 // Try to detect the correct property names
49- const sampleItem = sortedData [ 0 ] ;
124+ const sampleItem = finalData [ 0 ] ;
50125 const chargeKey = Object . keys ( sampleItem ) . find ( key =>
51126 key . includes ( 'charge' ) || key . includes ( 'battery' ) ||
52127 ( typeof sampleItem [ key ] === 'number' && sampleItem [ key ] >= 0 && sampleItem [ key ] <= 100 )
@@ -59,8 +134,8 @@ export const useBatteryHistory = (upsId) => {
59134
60135 if ( chargeKey && timeKey ) {
61136 console . log ( `Using detected keys: ${ chargeKey } for charge and ${ timeKey } for timestamp` ) ;
62- timestamps = sortedData . map ( item => item [ timeKey ] ) ;
63- charges = sortedData . map ( item => item [ chargeKey ] ) ;
137+ timestamps = finalData . map ( item => item [ timeKey ] ) ;
138+ charges = finalData . map ( item => item [ chargeKey ] ) ;
64139 } else {
65140 console . error ( 'Could not detect appropriate data keys' ) ;
66141 setBatteryHistory ( {
@@ -70,15 +145,47 @@ export const useBatteryHistory = (upsId) => {
70145 return ;
71146 }
72147 } else {
73- timestamps = sortedData . map ( item => item . timestamp ) ;
74- charges = sortedData . map ( item => item . charge_percent ) ;
148+ timestamps = finalData . map ( item => item . timestamp ) ;
149+ charges = finalData . map ( item => item . charge_percent ) ;
75150 }
76151
77- // Format timestamps for better display in a 7-day view
78- const formattedLabels = timestamps . map ( ts => {
79- const date = new Date ( ts ) ;
80- return date . toISOString ( ) ; // Return ISO string for proper date handling in the chart
152+ // Store the original Date objects for logging
153+ const dateObjects = timestamps . map ( ts => new Date ( ts ) ) ;
154+
155+ // Format timestamps for better display
156+ const formattedLabels = dateObjects . map ( date => {
157+ return date . toLocaleString ( [ ] , {
158+ month : 'short' ,
159+ day : 'numeric' ,
160+ hour : '2-digit' ,
161+ minute : '2-digit'
162+ } ) ;
81163 } ) ;
164+
165+ // Log the date range of the data
166+ if ( dateObjects . length > 0 ) {
167+ const oldestDate = dateObjects [ 0 ] ;
168+ const newestDate = dateObjects [ dateObjects . length - 1 ] ;
169+ console . log ( `Data date range: ${ oldestDate . toLocaleString ( ) } to ${ newestDate . toLocaleString ( ) } ` ) ;
170+
171+ // Calculate how many hours of data we have
172+ const hoursDiff = ( newestDate - oldestDate ) / ( 1000 * 60 * 60 ) ;
173+ console . log ( `Data spans approximately ${ hoursDiff . toFixed ( 1 ) } hours (${ ( hoursDiff / 24 ) . toFixed ( 1 ) } days)` ) ;
174+
175+ // Check if the data matches the requested time filter
176+ const now = new Date ( ) ;
177+ const requestedOldestDate = new Date ( now ) ;
178+ requestedOldestDate . setDate ( requestedOldestDate . getDate ( ) - days ) ;
179+ console . log ( `Requested date range: ${ requestedOldestDate . toLocaleString ( ) } to ${ now . toLocaleString ( ) } ` ) ;
180+
181+ // Calculate the difference between the oldest date in the data and the requested oldest date
182+ const diffHours = ( oldestDate - requestedOldestDate ) / ( 1000 * 60 * 60 ) ;
183+ console . log ( `Difference between requested and actual oldest date: ${ diffHours . toFixed ( 1 ) } hours` ) ;
184+
185+ if ( diffHours > 24 ) {
186+ console . warn ( `Warning: Data does not go back as far as requested. Missing approximately ${ diffHours . toFixed ( 1 ) } hours of data.` ) ;
187+ }
188+ }
82189
83190 setBatteryHistory ( {
84191 labels : formattedLabels ,
@@ -128,14 +235,16 @@ export const useBatteryHistory = (upsId) => {
128235
129236 useEffect ( ( ) => {
130237 if ( ! upsId ) return ;
131- fetchAndProcessData ( ) ;
132- } , [ upsId ] ) ;
238+ fetchAndProcessData ( currentTimeFilter ) ;
239+ } , [ upsId , currentTimeFilter ] ) ;
133240
134241 return {
135242 batteryHistory,
136243 loading,
137244 error,
138245 recordCurrentCharge,
139- refreshData : fetchAndProcessData
246+ refreshData : fetchAndProcessData ,
247+ currentTimeFilter,
248+ setTimeFilter : setCurrentTimeFilter
140249 } ;
141250} ;
0 commit comments