-
Notifications
You must be signed in to change notification settings - Fork 36
Expand file tree
/
Copy pathdata_store.py
More file actions
82 lines (66 loc) · 2.85 KB
/
Copy pathdata_store.py
File metadata and controls
82 lines (66 loc) · 2.85 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
from datetime import datetime
from os import path
from pandas import DataFrame
import pandas as pd
class DataStore:
def __init__(self):
self.reset()
def __bool__(self):
return len(self.lastrow) > 0
def reset(self):
self.lastrow = {}
self.data = DataFrame()
def append(self, row):
# Only log on state changes or significant events to reduce terminal spam
current_time = datetime.now()
should_log = False
# Log on state changes (on/off)
if self.lastrow and self.lastrow.get('is_on') != row['is_on']:
should_log = True
state = "ON" if row['is_on'] else "OFF"
print(f"{current_time.isoformat(sep=' ', timespec='seconds')} Device turned {state}")
# Log every 60 seconds during operation (instead of 10)
elif row.get('is_on') and (not hasattr(self, 'last_log_time') or
(current_time - self.last_log_time).total_seconds() > 60):
should_log = True
print(f"{current_time.isoformat(sep=' ', timespec='seconds')} Running: {self.format_duration(row['time'])} - V={row['voltage']:.3f} I={row['current']:.3f} Ah={row['cap_ah']:.2f}")
if should_log:
self.last_log_time = current_time
self.lastrow = row
# Create DataFrame with explicit columns to avoid FutureWarning
if self.data.empty:
# If data is empty, create DataFrame directly from row
self.data = DataFrame([row])
else:
# Otherwise use concat with matching columns
new_row_df = DataFrame([row], columns=self.data.columns)
self.data = pd.concat([self.data, new_row_df], ignore_index=True)
def write(self, basedir, prefix):
filename = "{}_raw_{}.csv".format(prefix, datetime.now().strftime("%Y%m%d_%H%M%S"))
full_path = path.join(basedir, filename)
export_rows = self.data.drop_duplicates()
if export_rows.shape[0]:
print(f"Saved raw data: {path.basename(full_path)}")
self.data.drop_duplicates().to_csv(full_path)
return full_path
else:
print("No data to save")
return None
def write_snapshot(self, basedir, prefix):
full_path = path.join(basedir, f"{prefix}_raw_autosave.csv")
export_rows = self.data.drop_duplicates()
if export_rows.shape[0]:
export_rows.to_csv(full_path)
return full_path
return None
def plot(self, **args):
return self.data.plot(**args)
def lastval(self, key):
return self.lastrow[key]
@staticmethod
def format_duration(total_seconds):
total = max(0, int(total_seconds))
hh = total // 3600
mm = (total % 3600) // 60
ss = total % 60
return f"{hh:02d}:{mm:02d}:{ss:02d}"