Aggiunti tempi di albe e tramonti con twilight zones

This commit is contained in:
ddnthemc 2025-04-08 12:37:14 +02:00
commit bbb4680c0a
15 changed files with 1752 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/crps/

3
.idea/.gitignore generated vendored Normal file
View file

@ -0,0 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml

8
.idea/OCR_Dome.iml generated Normal file
View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View file

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

7
.idea/misc.xml generated Normal file
View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Black">
<option name="sdkName" value="Python 3.11" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.11" project-jdk-type="Python SDK" />
</project>

8
.idea/modules.xml generated Normal file
View file

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/OCR_Dome.iml" filepath="$PROJECT_DIR$/.idea/OCR_Dome.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml generated Normal file
View file

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

3
README.md Normal file
View file

@ -0,0 +1,3 @@
Con ocr01.py acquisisci i dati dagli screenshot (in modo cumulativo su all_measures.json)
Poi con reload_data.py ottieni la versione ripulita: clean_data.json
Poi con show_data crei i file di visualizzazione.

1248
all_measurements_saved.json Normal file

File diff suppressed because it is too large Load diff

39
json_extensions.py Normal file
View file

@ -0,0 +1,39 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
import json
from decimal import Decimal
# from task_row_x import TaskRow, SimpleTaskRow
def load_from_json_file(infile):
with open(infile, 'r') as fin:
obj = json.load(fin)
return obj
class SpecialEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, Decimal):
return str(obj) # Or you could return str(obj) depending on your needs
# if isinstance(obj, TaskRow) or isinstance(obj, SimpleTaskRow):
if hasattr(obj, 'get_dict') and callable(getattr(obj, 'get_dict')):
return obj.get_dict()
if isinstance(obj, set):
return [str(v) for v in obj]
return super().default(obj)
def save_to_json_file(out_name, obj):
with open(out_name, 'w', encoding='utf-8', newline='\n') as fout:
json.dump(obj, fout, indent=4, cls=SpecialEncoder)
def save_to_json_str(obj):
return json.dumps(obj, indent=4, cls=SpecialEncoder)
def main():
pass
if __name__ == '__main__':
main()

83
ocr01.py Normal file
View file

@ -0,0 +1,83 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
import pytesseract
from PIL import Image
from pathlib import Path
from datetime import datetime
# import numpy as np
import colorsys
from json_extensions import save_to_json_file, load_from_json_file
save_file = Path('all_measurements.json')
# FOLDER = Path('C:/Mc/Dome/Telecamere/ScreenShots')
# FOLDER = Path('C:/Mc/Dome/Telecamere/ScreenShots2')
FOLDER = Path('C:/Mc/Dome/Telecamere/ScreenShots3')
CROPS = {
'batt_full': (351, 1109, 389, 101),
'name': (175, 143, 750, 109),
# 'batt': (48, 320, 25, 50),
'batt': (56, 345, 9, 2),
'perc': (83, 314, 123, 60),
}
def available_screenshot(base_folder: Path):
for f in base_folder.iterdir():
if f.is_file() and f.suffix == '.jpg' and f.stem.startswith('Screenshot') and f.stem.endswith('0a7d545a89c1640e78c89a2ce00d525b'):
yield f
def main(base_folder: Path, out_folder=Path('crps')):
# for sc in sorted(available_screenshot(base_folder), key=lambda x:x.stem):
found = False
n = 0
if save_file.is_file():
measures = load_from_json_file(save_file)
else:
measures = []
for sc in available_screenshot(base_folder):
n += 1
_, f_date, _ = sc.stem.split('_')
dt = datetime.strptime(f_date[:-3], '%Y-%m-%d-%H-%M-%S')
# obj = {'dt': dt}
obj = {'epoch': dt.timestamp()}
# if f_date != '2025-03-16-07-59-52-21':
# continue
# print(sc.stem)
src_img = Image.open(sc)
for k, crp in CROPS.items():
x0, y0, w, h = crp
x1 = x0 + w
y1 = y0 + h
cropped = src_img.crop((x0, y0, x1, y1))
if k == 'batt':
# new_name = f'{k}_{f_date}.png'
# cropped.save(out_folder / new_name)
tot, grey = 0, 0
for p in cropped.getdata():
tot += 1
r, g, b = p
h, s, v = colorsys.rgb_to_hsv(r / 255, g / 255, b / 255)
if s < 0.1 and v > 0.1:
grey += 1
v = grey / tot
# print(f'{v:.1f}')
obj['charging'] = v > 0.8
# obj['charging'] = is_mostly_white(cropped)
if k != 'batt':
text = pytesseract.image_to_string(cropped)
obj[k] = text
if k == 'batt_full' and len(text) > 3:
found = True
print(f'{f_date}: {obj}')
measures.append(obj)
save_to_json_file('all_measurements.json', measures)
return
if __name__ == '__main__':
main(FOLDER)

39
plt_example.py Normal file
View file

@ -0,0 +1,39 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
import datetime
def main():
# Sample data
epoch_times = [1696000000, 1696086400, 1696172800, 1696259200] # Epoch seconds
y_values = [10, 20, 15, 25] # Some y-axis values
# Convert epoch times to datetime objects
dates = [datetime.datetime.fromtimestamp(ts) for ts in epoch_times]
# Create the plot
fig, ax = plt.subplots()
ax.plot(dates, y_values, marker='o', linestyle='-')
# 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()) # Automatically adjusts for readability
ax.xaxis.set_major_formatter(
mdates.ConciseDateFormatter(ax.xaxis.get_major_locator()))
# Rotate date labels for better visibility
plt.xticks(rotation=45)
# Labels and title
plt.xlabel("Date & Time")
plt.ylabel("Values")
plt.title("Epoch to Human Readable Time Plot")
# Show the plot
plt.show()
if __name__ == '__main__':
main()

33
reload_data.py Normal file
View file

@ -0,0 +1,33 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
from json_extensions import load_from_json_file, save_to_json_file
def main():
clean_data: dict[str, list] = {}
obj = load_from_json_file('all_measurements.json')
names = set()
for row in obj:
name = row.get('name', '').strip('\n')
perc_s = row.get('perc', '').strip('\n')
charging = row.get('charging')
epoch = row.get('epoch')
batt_full_s = row.get('batt_full', '').strip('\n')
batt_full = 'The battery is full' in batt_full_s
if '%' not in perc_s:
raise ValueError(f'Missing % in {row}')
prc = int(perc_s.split('%', maxsplit=1)[0])
names.add(name)
if name not in clean_data:
clean_data[name] = []
new_row = {'epoch': epoch, 'soc': prc, 'battery_full': batt_full, 'charging': charging}
print(name, new_row)
clean_data[name].append(new_row)
print(names)
for lst in clean_data.values():
lst.sort(key=lambda x: x['epoch'])
save_to_json_file('clean_data.json', clean_data)
if __name__ == '__main__':
main()

207
show_data.py Normal file
View file

@ -0,0 +1,207 @@
#!/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)

61
test_twilight.py Normal file
View file

@ -0,0 +1,61 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
import matplotlib.pyplot as plt
import numpy as np
import matplotlib.dates as mdates
from datetime import datetime, timedelta
from astral import LocationInfo
from astral.sun import sun
def main():
# Set your location
city = LocationInfo("Rome", "Italy", "Europe/Rome", 44.448066, 11.270639)
# Choose the date
# date = datetime(2023, 3, 29)
# dawn: 2023-03-29 06:32:45.166761+02:00
# sunrise: 2023-03-29 07:02:31.106176+02:00
# noon: 2023-03-29 13:19:52+02:00
# sunset: 2023-03-29 19:37:45.931604+02:00
# dusk: 2023-03-29 20:07:37.090448+02:00
date = datetime(2023, 3, 29)
# Get solar times
s = sun(city.observer, date=date, tzinfo=city.timezone)
for k, v in s.items():
print(f'{k}: {v}')
dawn = s['dawn']
sunrise = s['sunrise']
sunset = s['sunset']
dusk = s['dusk']
# Generate time series data for one day
times = [date + timedelta(minutes=15 * i) for i in range(96 * 1)]
values = np.sin(np.linspace(0, 4 * np.pi, len(times))) # Some mock data
# Create the plot
fig, ax = plt.subplots(figsize=(10, 5))
ax.plot(times, values, label="Sensor Data", color='tab:blue')
# Plot twilight periods as vertical bands
ax.axvspan(dawn, sunrise, color='lightskyblue', alpha=0.3, label='Morning Twilight')
ax.axvspan(sunset, dusk, color='lightskyblue', alpha=0.3, label='Evening Twilight')
# Mark sunrise and sunset
ax.axvline(sunrise, color='orange', linestyle='--', label='Sunrise')
ax.axvline(sunset, color='red', linestyle='--', label='Sunset')
# Formatting
ax.set_title(f"Daylight and Twilight - {city.name} on {date.strftime('%Y-%m-%d')}")
ax.set_xlabel("Time")
ax.set_ylabel("Sensor Value")
ax.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M'))
plt.xticks(rotation=45)
plt.legend()
plt.tight_layout()
plt.show()
if __name__ == '__main__':
main()