Files
dashboard-cpsp/scripts/analyze_iot_api_fast.py
T
2026-08-26 13:46:05 +07:00

112 lines
4.3 KiB
Python

"""Fast sample scan of IoT flocks API — day/date mapping without full pagination."""
import json
import urllib.request
from collections import defaultdict
from datetime import datetime, timedelta, timezone
BASE = "https://dashboard.cpsp.id/api/iot/flocks/"
CYCLE_START = datetime(2026, 5, 22).date()
TZ = timezone(timedelta(hours=7))
def parse_dt(value: str) -> datetime:
return datetime.fromisoformat(value.replace("Z", "+00:00"))
def fetch_page(page: int) -> dict:
with urllib.request.urlopen(f"{BASE}?page={page}", timeout=60) as resp:
return json.loads(resp.read())
def summarize_records(records: list) -> None:
by_day: dict[int, list] = defaultdict(list)
for r in records:
day = r["payload"]["data"].get("day")
if day is not None:
by_day[day].append(r)
print(f" unique days: {len(by_day)} range {min(by_day)}..{max(by_day)}")
for day in sorted(by_day)[:3]:
r = max(by_day[day], key=lambda x: parse_dt(x["fetched_at"]))
d = r["payload"]["data"]
cal = CYCLE_START + timedelta(days=day - 1)
print(
f" day {day} -> {cal} | wind={d.get('wind')} hum={d.get('humidity')} "
f"temp={d.get('actualTemperature')} water={d.get('water')} HSI={d.get('HSI')}"
)
if len(by_day) > 6:
print(" ...")
for day in sorted(by_day)[-3:]:
r = max(by_day[day], key=lambda x: parse_dt(x["fetched_at"]))
d = r["payload"]["data"]
cal = CYCLE_START + timedelta(days=day - 1)
print(
f" day {day} -> {cal} | wind={d.get('wind')} hum={d.get('humidity')} "
f"temp={d.get('actualTemperature')} water={d.get('water')} HSI={d.get('HSI')}"
)
def main() -> None:
p1 = fetch_page(1)
total = p1["count"]
page_size = len(p1["results"])
last_page = (total + page_size - 1) // page_size
print(f"API total={total} page_size={page_size} pages={last_page}")
r0 = p1["results"][0]
d0 = r0["payload"]["data"]
coop = d0.get("coop") or {}
print(f"flock_id={r0['flock_id']} floor={d0.get('name')} site={coop.get('kode')}")
print(f"kandang field (Mongo id)={d0.get('kandang')}")
# Sample: first pages (newest), last pages (oldest), and mid pages
sample_pages = sorted({1, 2, 3, 10, 50, 100, 200, 400, 600, last_page, last_page - 1, last_page - 2})
all_records = []
for page in sample_pages:
if page < 1 or page > last_page:
continue
data = fetch_page(page)
all_records.extend(data["results"])
days = {r["payload"]["data"].get("day") for r in data["results"]}
fdates = {parse_dt(r["fetched_at"]).astimezone(TZ).date() for r in data["results"]}
print(f"page {page:4d}: days={min(days)}..{max(days)} fetched_dates={min(fdates)}..{max(fdates)}")
# Roll up sampled data: latest fetched_at per cycle day
daily: dict[int, dict] = {}
for r in all_records:
day = r["payload"]["data"].get("day")
if day is None:
continue
ts = parse_dt(r["fetched_at"])
if day not in daily or ts > daily[day]["ts"]:
daily[day] = {"ts": ts, "r": r}
print(f"\nFrom sample: {len(daily)} unique cycle days seen")
missing = [d for d in range(1, 50) if d not in daily]
print(f"Missing in sample (1..49): {missing}")
print("\nField mapping -> iot_panel (exclude experience_temperature):")
print(" date = cycle_start + (day - 1) # 2026-05-22 + day-1")
print(" wind_speed = payload.data.wind")
print(" humidity = payload.data.humidity # likely /10 for %")
print(" water_total = payload.data.water")
print(" average_temperature = payload.data.actualTemperature # likely /10 for °C")
print(" experience_temperature = formula (HSI? TBD)")
print("\nSample rollup table:")
print(f"{'day':>3} {'date':>10} {'wind':>5} {'hum':>6} {'temp_raw':>8} {'water':>6} {'HSI':>7}")
for day in range(1, 50):
cal = CYCLE_START + timedelta(days=day - 1)
entry = daily.get(day)
if not entry:
continue
d = entry["r"]["payload"]["data"]
print(
f"{day:3d} {cal} {d.get('wind', 0):5} {d.get('humidity', 0):6} "
f"{d.get('actualTemperature', 0):8} {d.get('water', 0):6} {d.get('HSI', 0):7.2f}"
)
if __name__ == "__main__":
main()