"""Publish sample locate points to the UlHub backend via MQTT. The backend subscribes to devices/# and expects points at devices/{mqttUsername}/points with a JSON body: {"serial": "...", "ticket": "TKT-...", "points": [{"lat": .., "lng": .., "ts": "ISO8601", ...}]} The MQTT username identifies the publisher (app/gateway) and its org; "serial" names the locator receiver the readings came from (auto-registered on first sight). Points for an unknown ticket auto-create a stub job (source=DEVICE). """ import random import json import os import time from datetime import datetime, timezone import paho.mqtt.client as mqtt BROKER_HOST = os.getenv("MQTT_HOST", "127.0.0.1") BROKER_PORT = int(os.getenv("MQTT_PORT", "1883")) USERNAME = os.getenv("MQTT_USERNAME", "testuser") PASSWORD = os.getenv("MQTT_PASSWORD", "testpass") SERIAL = os.getenv("SERIAL", "DEMO-0001") TICKET = os.getenv("TICKET", "TKT-2026-0001") INTERVAL = float(os.getenv("MQTT_INTERVAL", "2")) # Walk northeast from this location, one point per interval START_LAT = float(os.getenv("START_LAT", "33.15012345")) START_LNG = float(os.getenv("START_LNG", "-96.83512345")) TOPIC = f"devices/{USERNAME}/points" client = mqtt.Client() client.username_pw_set(USERNAME, PASSWORD) client.connect(BROKER_HOST, BROKER_PORT, 60) client.loop_start() try: seq = 0 while True: payload = { "serial": SERIAL, "ticket": TICKET, "points": [ { "lat": START_LAT + seq * 0.0000135, "lng": START_LNG + seq * 0.0000042, "alt": 187.4 + seq * 0.02, "fix": "FIXED_RTK", "hAcc": 0.014, "vAcc": 0.021, "sats": random.randint(18, 26), "hdop": 0.7, "depth": round(1.1 + random.uniform(0, 0.3), 2), "freqHz": 33000, "currentMa": round(50 - seq * 0.4 + random.uniform(-1, 1), 1), "signalDb": round(62 - seq * 0.2 + random.uniform(-0.5, 0.5), 1), "gainDb": 40, "mode": "PEAK", "compassDeg": round(17.5 + random.uniform(-3, 3), 1), "distortionPct": round(random.uniform(2, 8), 1), "utility": "GAS", "seq": seq + 1, "ts": datetime.now(timezone.utc).isoformat(), } ], } client.publish(TOPIC, json.dumps(payload), qos=1) print(f"published point {seq + 1} to {TOPIC} (ticket {TICKET})") seq += 1 time.sleep(INTERVAL) except KeyboardInterrupt: print("stopped") finally: client.loop_stop() client.disconnect()