import argparse import json import logging import random import time from urllib.parse import urlparse import paho.mqtt.client as mqtt from config import build_sender_dependencies from model import DrillingRealtimeData logger = logging.getLogger(__name__) def parse_broker(broker): if not broker: raise ValueError("broker is required") if "://" not in broker: broker = "tcp://" + broker parsed = urlparse(broker) host = parsed.hostname or "localhost" port = parsed.port or 1883 scheme = (parsed.scheme or "tcp").lower() return scheme, host, port def rand_int(a, b): return random.randint(a, b) def rand_float(a, b, digits=2): return round(random.uniform(a, b), digits) def build_random_payload(equipment_code): entity = DrillingRealtimeData.empty(wellid=equipment_code) entity = DrillingRealtimeData( ts=entity.ts, wellid=entity.wellid, stknum=rand_int(0, 500), recid=rand_int(0, 100000), seqid=rand_int(0, 100000), actual_date=entity.actual_date, actual_time=entity.actual_time, actcod=rand_int(0, 9), deptbitm=rand_float(0, 5000), deptbitv=rand_float(0, 5000), deptmeas=rand_float(0, 5000), deptvert=rand_float(0, 5000), blkpos=rand_float(0, 100), ropa=rand_float(0, 200), hkla=rand_float(0, 500), hklx=rand_float(0, 500), woba=rand_float(0, 200), wobx=rand_float(0, 200), torqa=rand_float(0, 200), torqx=rand_float(0, 200), rpma=rand_int(0, 300), sppa=rand_float(0, 5000), chkp=rand_float(0, 5000), spm1=rand_int(0, 200), spm2=rand_int(0, 200), spm3=rand_int(0, 200), tvolact=rand_float(0, 20000), tvolcact=rand_float(0, 20000), mfop=rand_int(0, 1000), mfoa=rand_float(0, 1000), mfia=rand_float(0, 1000), mdoa=rand_float(0, 1000), mdia=rand_float(0, 1000), mtoa=rand_float(0, 1000), mtia=rand_float(0, 1000), mcoa=rand_float(0, 1000), mcia=rand_float(0, 1000), stkc=rand_int(0, 200), lagstks=rand_int(0, 200), deptretm=rand_float(0, 5000), gasa=rand_float(0, 100), space1=rand_float(0, 10), space2=rand_float(0, 10), space3=rand_float(0, 10), space4=rand_float(0, 10), space5=rand_float(0, 10), ) return entity.to_payload(equipment_code) def run_sender(args, deps): mqtt_config = deps.config.mqtt tms_config = deps.config.tms scheme, host, port = parse_broker(mqtt_config.broker) logger.info("MQTT sender config broker=%s://%s:%s client_id=%s pub_topic=%s interval=%ss", scheme, host, port, mqtt_config.sender_client_id, mqtt_config.pub_topic, args.interval) client = mqtt.Client(client_id=mqtt_config.sender_client_id, clean_session=True) if mqtt_config.username is not None: client.username_pw_set(mqtt_config.username, mqtt_config.password) if scheme in ("ssl", "tls", "mqtts"): client.tls_set() def on_disconnect(c, userdata, rc): logger.info("Disconnected callback rc=%s", rc) client.on_disconnect = on_disconnect client.connect(host, port, keepalive=tms_config.keepalive) client.loop_start() try: if not mqtt_config.pub_topic: logger.warning("pub-topic is empty; nothing to publish") return seq = 0 while True: seq += 1 payload = build_random_payload(tms_config.device_code) client.publish(mqtt_config.pub_topic, json.dumps(payload, ensure_ascii=True)) logger.info("TX %s #%s", mqtt_config.pub_topic, seq) if args.count and seq >= args.count: break time.sleep(args.interval) except KeyboardInterrupt: logger.info("Sender interrupted") finally: client.loop_stop() client.disconnect() logger.info("Sender stopped") def add_arguments(parser): parser.add_argument("--config", default="config.yaml", help="Path to config yaml") parser.add_argument("--interval", type=float, default=3.0, help="Publish interval (seconds)") parser.add_argument("--count", type=int, default=0, help="Publish count (0 = forever)") def main(argv=None): parser = argparse.ArgumentParser(description="MQTT random data sender") add_arguments(parser) args = parser.parse_args(argv) deps = build_sender_dependencies(args.config) run_sender(args, deps) if __name__ == "__main__": main()