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

110 lines
4.0 KiB
Python

"""Analyze dashboard.cpsp.id IoT flocks API for date/day mapping."""
import json
import urllib.request
from collections import Counter, defaultdict
from datetime import datetime, timedelta, timezone
BASE = "https://dashboard.cpsp.id/api/iot/flocks/"
CYCLE_START = datetime(2026, 5, 22).date()
CYCLE_END = datetime(2026, 7, 9).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:
url = f"{BASE}?page={page}"
with urllib.request.urlopen(url, timeout=60) as resp:
return json.loads(resp.read())
def main() -> None:
meta = fetch_page(1)
total = meta["count"]
page_size = len(meta["results"])
last_page = (total + page_size - 1) // page_size
print(f"total={total} page_size={page_size} last_page={last_page}")
sample_pages = [1, 2, 3, last_page, last_page - 1]
records = []
for page in sample_pages:
data = fetch_page(page)
records.extend(data["results"])
print(f" fetched page {page}: {len(data['results'])} rows")
flock_ids = Counter(r["flock_id"] for r in records)
print(f"unique flock_ids in sample: {dict(flock_ids)}")
r0 = records[0]["payload"]["data"]
coop = r0.get("coop") or {}
print(f"coop kode={coop.get('kode')} name floor={r0.get('name')} kandang={r0.get('kandang')}")
by_day = defaultdict(list)
by_fetch_date = defaultdict(list)
for r in records:
d = r["payload"]["data"]
day = d.get("day")
if day is not None:
by_day[day].append(r)
fetched = r.get("fetched_at") or d.get("lastUpdate")
if fetched:
cal = parse_dt(fetched).astimezone(TZ).date()
by_fetch_date[cal].append(r)
print(f"day range: {min(by_day)}..{max(by_day)} ({len(by_day)} unique)")
print(f"fetched_at date range: {min(by_fetch_date)}..{max(by_fetch_date)} ({len(by_fetch_date)} unique)")
print("\nSample day -> metrics (first record per day):")
for day in sorted(by_day):
if day not in (1, 2, 3, 34, 35, 36, 48, 49):
continue
d = by_day[day][0]["payload"]["data"]
fetched = by_day[day][0].get("fetched_at", "")[:19]
cal = CYCLE_START + timedelta(days=day - 1)
print(
f" day {day:2d} (cycle cal {cal}) fetched={fetched} "
f"wind={d.get('wind')} hum={d.get('humidity')} temp={d.get('actualTemperature')} "
f"water={d.get('water')} HSI={d.get('HSI')}"
)
# Full scan for one flock: aggregate one row per cycle day using `day` field
print("\nScanning all pages for daily rollup by `day` (last snapshot per day)...")
daily: dict[int, dict] = {}
for page in range(1, last_page + 1):
for r in fetch_page(page)["results"]:
d = r["payload"]["data"]
day = d.get("day")
if day is None:
continue
fetched = r.get("fetched_at")
if not fetched:
continue
ts = parse_dt(fetched)
prev = daily.get(day)
if prev is None or ts > prev["ts"]:
daily[day] = {"ts": ts, "r": r}
print(f"Collected {len(daily)} unique cycle days from full API")
missing = [d for d in range(1, 50) if d not in daily]
print(f"Missing days 1..49: {missing}")
print("\nFull cycle rollup (mapped to calendar via start 2026-05-22):")
print(f"{'day':>3} {'date':>10} {'wind':>6} {'humidity':>8} {'avg_temp':>8} {'water':>8} {'HSI':>8}")
for day in range(1, 50):
entry = daily.get(day)
cal = CYCLE_START + timedelta(days=day - 1)
if not entry:
print(f"{day:3d} {cal} — missing —")
continue
d = entry["r"]["payload"]["data"]
print(
f"{day:3d} {cal} {d.get('wind', 0):6} {d.get('humidity', 0):8} "
f"{d.get('actualTemperature', 0):8} {d.get('water', 0):8} {d.get('HSI', 0):8.2f}"
)
if __name__ == "__main__":
main()