# Python 3.10+ / Google Colab. Install first: pip install requests import csv import getpass import os import time from datetime import datetime, timedelta, timezone import requests BASE_URL = os.environ.get("JK_API_BASE_URL", "https://jk.cyberlative.com/api/v1/ml").rstrip("/") TOKEN = os.environ.get("JK_ML_API_TOKEN") or getpass.getpass("Client API token: ") HEADERS = {"Authorization": "Bearer " + TOKEN.strip()} def get(path, params=None): for attempt in range(3): response = requests.get(BASE_URL + path, headers=HEADERS, params=params, timeout=30, allow_redirects=False) if response.status_code == 429 and attempt < 2: time.sleep(max(1, int(response.headers.get("Retry-After", "60")))) continue response.raise_for_status() if response.status_code != 200: raise RuntimeError("Expected HTTP 200; check BASE_URL uses the final HTTPS address") return response.json() sites = get("/sites")["sites"] sensors = get("/sensors")["sensors"] print("Sites:", len(sites), "Sensors:", len(sensors)) if not sensors: raise SystemExit("No sensors configured. Ask the administrator to add one.") # Choose an enabled sensor. Set JK_SENSOR_ID to use a known active probe. sensor = next((s for s in sensors if s["enabled"]), sensors[0]) SENSOR_ID = os.environ.get("JK_SENSOR_ID", sensor["id"]) print("Selected sensor ID:", SENSOR_ID) print("Latest values:", get("/snapshot", {"sensorIds": SENSOR_ID})) end = datetime.now(timezone.utc) params = {"sensorIds": SENSOR_ID, "from": (end - timedelta(days=1)).isoformat(), "to": end.isoformat(), "resolution": "raw", "limit": 2000} rows = [] while True: page = get("/readings", params) rows.extend(page["data"]) if not page["hasMore"]: break params["cursor"] = page["nextCursor"] # Keep the original filters/from/to. print("Readings in the last 24 hours:", len(rows)) for row in rows[:5]: print(row) if rows: with open("readings.csv", "w", newline="", encoding="utf-8") as output: writer = csv.DictWriter(output, fieldnames=list(rows[0])) writer.writeheader() writer.writerows(rows) print("Saved readings.csv") else: print("No readings in this window. Choose another sensor or a longer period.")