112 lines
4.3 KiB
Python
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()
|