207 lines
7.3 KiB
Python
207 lines
7.3 KiB
Python
#!/usr/bin/python
|
|
# -*- coding: utf-8 -*-
|
|
import matplotlib.pyplot as plt
|
|
import matplotlib.dates as mdates
|
|
import matplotlib.patches as mpatches
|
|
|
|
from astral import LocationInfo
|
|
from astral.sun import sun
|
|
|
|
import datetime
|
|
from json_extensions import load_from_json_file
|
|
|
|
|
|
city = LocationInfo("Rome", "Italy", "Europe/Rome", 44.448066, 11.270639)
|
|
|
|
|
|
def main(data):
|
|
# Sample data
|
|
# epoch_times = [1696000000, 1696086400, 1696172800, 1696259200] # Epoch seconds
|
|
# y_values = [10, 20, 15, 25] # Some y-axis values
|
|
|
|
# Create the plot
|
|
fig, ax = plt.subplots(tight_layout=False, figsize=(30, 10))
|
|
earliest = None
|
|
latest = None
|
|
for name_raw, serie in data.items():
|
|
if name_raw in ('Security Camera', 'Ext Front'):
|
|
continue
|
|
name = {'Front door': 'Sample #1 No PV panel', 'Ext2': 'Sample #2 with PV Panel', }.get(name_raw, name_raw)
|
|
dates = [datetime.datetime.fromtimestamp(row['epoch']) for row in serie]
|
|
soc_v = [row['soc'] for row in serie]
|
|
if name_raw == 'Front door':
|
|
dates = dates[3:]
|
|
soc_v = soc_v[3:]
|
|
mi = min(dates)
|
|
ma = max(dates)
|
|
if earliest is None:
|
|
earliest = mi
|
|
latest = ma
|
|
else:
|
|
earliest = min(earliest, mi)
|
|
latest = max(latest, ma)
|
|
|
|
# charging = [row['charging'] for row in serie]
|
|
# batt_full = [row['battery_full'] for row in serie]
|
|
#
|
|
# sizes = []
|
|
# for c1, c2 in zip(charging, batt_full):
|
|
# if c1 and c2:
|
|
# sizes.append(100) # Example: Both conditions true
|
|
# elif c1:
|
|
# sizes.append(200) # Example: Only condition 1 true
|
|
# elif c2:
|
|
# sizes.append(300) # Example: Only condition 2 true
|
|
# else:
|
|
# sizes.append(400) # Example: Both conditions false
|
|
#
|
|
|
|
ax.plot(dates, soc_v, '-o', lw=3, label=name)
|
|
|
|
# for x, y, color in zip(dates, soc_v, sizes):
|
|
|
|
# ax.plot(dates, y_values, marker='o', linestyle='-')
|
|
|
|
print(earliest, latest)
|
|
current_day = earliest
|
|
first_time = True
|
|
while current_day < latest:
|
|
# print(current_day)
|
|
# Get solar times
|
|
s = sun(city.observer, date=current_day, tzinfo=city.timezone)
|
|
dawn = s['dawn']
|
|
sunrise = s['sunrise']
|
|
sunset = s['sunset']
|
|
dusk = s['dusk']
|
|
if first_time:
|
|
ax.axvspan(dawn, sunrise, color='deepskyblue', alpha=0.3, label='Twilight (-6°)')
|
|
ax.axvspan(sunset, dusk, color='deepskyblue', alpha=0.3)
|
|
ax.axvline(sunrise, color='orange', linestyle='--', label='Sunrise')
|
|
ax.axvline(sunset, color='red', linestyle='--', label='Sunset')
|
|
first_time = False
|
|
else:
|
|
ax.axvspan(dawn, sunrise, color='deepskyblue', alpha=0.3)
|
|
ax.axvspan(sunset, dusk, color='deepskyblue', alpha=0.3)
|
|
ax.axvline(sunrise, color='orange', linestyle='--')
|
|
ax.axvline(sunset, color='red', linestyle='--')
|
|
|
|
current_day += datetime.timedelta(days=1)
|
|
|
|
# Format the x-axis as date
|
|
# ax.xaxis.set_major_formatter(mdates.DateFormatter('%Y-%m-%d\n%H:%M:%S')) # Customize as needed
|
|
ax.xaxis.set_major_locator(
|
|
mdates.AutoDateLocator(minticks=30, maxticks=60)) # Automatically adjusts for readability
|
|
ax.xaxis.set_major_formatter(mdates.ConciseDateFormatter(ax.xaxis.get_major_locator()))
|
|
|
|
x_tail = datetime.datetime(year=2025, month=4, day=7, hour=7, minute=20)
|
|
y_tail = 85
|
|
x_head = datetime.datetime(year=2025, month=4, day=7, hour=6, minute=59)
|
|
y_head = 100
|
|
dx = x_head - x_tail
|
|
dy = y_head - y_tail
|
|
|
|
# Rotate date labels for better visibility
|
|
# plt.xticks(rotation=45)
|
|
|
|
arrow = mpatches.FancyArrowPatch((x_tail, y_tail), (x_head, y_head), mutation_scale=50)
|
|
ax.add_patch(arrow)
|
|
|
|
# Labels and title
|
|
ax.grid()
|
|
ax.legend(loc='lower right', framealpha=1.0)
|
|
plt.xlabel("Date & Time")
|
|
plt.ylabel("Reported State of Charge [%]")
|
|
plt.title('Camera battery behaviour')
|
|
|
|
img_num = 1
|
|
out_name = f'{img_num}_f11.png'
|
|
img_num += 1
|
|
fig.savefig(out_name, dpi=150)
|
|
|
|
st1 = datetime.datetime(year=2025, month=3, day=29)
|
|
end1 = datetime.datetime(year=2025, month=4, day=8, hour=12)
|
|
ax.set_xlim(st1, end1)
|
|
txt = f'Problems:\nSample#2: After FW upgrade the problem looks the same\nSample#1: Discharge is not monotonic.'
|
|
annt = ax.text(0.3, 0.1, txt, ha='left', fontsize=20, bbox={'facecolor': 'lightgray', 'alpha': 0.85, 'pad': 5},
|
|
transform=ax.transAxes)
|
|
# annt.set_text(txt)
|
|
# print(txt)
|
|
out_name = f'{img_num}_overview.png'
|
|
# out_name_svg = f'{img_num}_overview.svg'
|
|
out_name_pdf = f'{img_num}_overview.pdf'
|
|
# fig.savefig(out_name_svg)
|
|
fig.savefig(out_name_pdf)
|
|
img_num += 1
|
|
fig.savefig(out_name, dpi=200)
|
|
|
|
#
|
|
# st1 = datetime.datetime(year=2025, month=3, day=1)
|
|
# end1 = datetime.datetime(year=2025, month=3, day=3)
|
|
# ax.set_xlim(st1, end1)
|
|
# txt = f'We noticed battery level anomaly'
|
|
# # print(txt)
|
|
# annt = ax.text(0.1, 0.2, txt, ha='left', fontsize=20, bbox={'facecolor': 'cyan', 'alpha': 0.7, 'pad': 5},
|
|
# transform=ax.transAxes)
|
|
# print(annt, type(annt))
|
|
# out_name = f'{img_num}_first_anomaly.png'
|
|
# img_num += 1
|
|
# fig.savefig(out_name, dpi=150)
|
|
# # annt.remove()
|
|
#
|
|
# st1 = datetime.datetime(year=2025, month=3, day=17)
|
|
# end1 = datetime.datetime(year=2025, month=3, day=19)
|
|
# ax.set_xlim(st1, end1)
|
|
# txt = f'We noticed battery level anomaly Again!'
|
|
# annt.set_text(txt)
|
|
# # print(txt)
|
|
# out_name = f'{img_num}_second_anomaly.png'
|
|
# img_num += 1
|
|
# fig.savefig(out_name, dpi=150)
|
|
#
|
|
# st1 = datetime.datetime(year=2025, month=3, day=19)
|
|
# end1 = datetime.datetime(year=2025, month=4, day=1)
|
|
# ax.set_xlim(st1, end1)
|
|
# txt = f'We unplugged the PV panel as asked by supplier'
|
|
# annt.set_text(txt)
|
|
# # print(txt)
|
|
# out_name = f'{img_num}_unplugged.png'
|
|
# img_num += 1
|
|
# fig.savefig(out_name, dpi=150)
|
|
#
|
|
# st1 = datetime.datetime(year=2025, month=3, day=29)
|
|
# end1 = datetime.datetime(year=2025, month=4, day=1)
|
|
# ax.set_xlim(st1, end1)
|
|
# txt = f'We started testing a second sample'
|
|
# annt.set_text(txt)
|
|
# # print(txt)
|
|
# out_name = f'{img_num}_Sample2.png'
|
|
# img_num += 1
|
|
# fig.savefig(out_name, dpi=150)
|
|
#
|
|
# st1 = datetime.datetime(year=2025, month=3, day=30, hour=17, minute=30)
|
|
# end1 = datetime.datetime(year=2025, month=3, day=31, hour=9, minute=30)
|
|
# ax.set_xlim(st1, end1)
|
|
# txt = f'There are Anomalies in the evening and in the morning'
|
|
# annt.set_text(txt)
|
|
# # print(txt)
|
|
# out_name = f'{img_num}_Sample2_detail1.png'
|
|
# img_num += 1
|
|
# fig.savefig(out_name, dpi=150)
|
|
#
|
|
# st1 = datetime.datetime(year=2025, month=3, day=31, hour=15, minute=30)
|
|
# end1 = datetime.datetime(year=2025, month=4, day=1, hour=10)
|
|
# ax.set_xlim(st1, end1)
|
|
# txt = f'Second day Sample#2 still show anomaly\nSample#1 has increasing battery level (Impossible)'
|
|
# annt.set_text(txt)
|
|
# # print(txt)
|
|
# out_name = f'{img_num}_Sample2_detail2.png'
|
|
# img_num += 1
|
|
# fig.savefig(out_name, dpi=150)
|
|
|
|
# Show the plot
|
|
# plt.show()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
cln_data = load_from_json_file('clean_data.json')
|
|
main(cln_data)
|