···11+(** OwnTracks MQTT Location Subscriber
22+33+ This example connects to an MQTT broker and subscribes to OwnTracks
44+ location messages, pretty-printing the received data.
55+66+ Usage:
77+ owntracks-subscriber [OPTIONS]
88+99+ Options can also be set via environment variables:
1010+ MQTT_HOST - MQTT broker hostname (default: 127.0.0.1)
1111+ MQTT_PORT - MQTT broker port (default: 1883, or 8883 with --tls)
1212+ MQTT_TLS - Enable TLS (set to any value)
1313+ MQTT_USER - MQTT username (optional)
1414+ MQTT_PASSWORD - MQTT password (optional)
1515+ MQTT_CLIENT_ID - MQTT client ID (optional)
1616+1717+ See vendor/git/recorder for the OwnTracks Recorder reference implementation.
1818+*)
1919+2020+open Cmdliner
2121+2222+let topic =
2323+ let doc = "OwnTracks topic to subscribe to. Supports MQTT wildcards." in
2424+ let env = Cmd.Env.info "OT_TOPIC" ~doc in
2525+ Arg.(value & opt string "owntracks/#" &
2626+ info ["t"; "topic"] ~docv:"TOPIC" ~doc ~env)
2727+2828+let run mqtt topic =
2929+ Fmt_tty.setup_std_outputs ();
3030+ Logs.set_level (Some Logs.Info);
3131+ Logs.set_reporter (Logs_fmt.reporter ());
3232+3333+ let conn = mqtt.Mqtte_eio.Cmd.connection in
3434+ let config = mqtt.Mqtte_eio.Cmd.config in
3535+ let pool_config = mqtt.Mqtte_eio.Cmd.pool_config in
3636+3737+ Logs.info (fun m -> m "OwnTracks MQTT Subscriber");
3838+ Logs.info (fun m -> m "Connecting to %s:%d%s" conn.host conn.port
3939+ (if conn.tls then " (TLS)" else ""));
4040+ Logs.info (fun m -> m "Subscribing to: %s" topic);
4141+4242+ Eio_main.run @@ fun env ->
4343+ Mirage_crypto_rng_unix.use_default ();
4444+ Eio.Switch.run @@ fun sw ->
4545+4646+ let on_message msg =
4747+ let open Mqtte_eio.Client in
4848+ let payload_with_topic =
4949+ let payload = msg.payload in
5050+ if String.length payload > 0 && payload.[0] = '{' then
5151+ let topic_json = Printf.sprintf "{\"topic\":%S," msg.topic in
5252+ topic_json ^ String.sub payload 1 (String.length payload - 1)
5353+ else
5454+ payload
5555+ in
5656+ match Owntracks.decode_message payload_with_topic with
5757+ | Ok message ->
5858+ Format.printf "%a@." Owntracks.pp_message message
5959+ | Error err ->
6060+ Logs.warn (fun m -> m "Failed to parse message on [%s]: %s"
6161+ msg.topic err);
6262+ Logs.debug (fun m -> m "Raw payload: %s" msg.payload)
6363+ in
6464+6565+ let on_disconnect () =
6666+ Logs.warn (fun m -> m "Disconnected from broker")
6767+ in
6868+6969+ let net = Eio.Stdenv.net env in
7070+ let clock = Eio.Stdenv.clock env in
7171+7272+ let pool = Mqtte_eio.Cmd.create_pool ~sw ~net ~clock
7373+ ~tls:conn.tls ~insecure:conn.insecure ~pool_config () in
7474+ let endpoint = Mqtte_eio.Cmd.endpoint conn in
7575+7676+ let client = Mqtte_eio.Client.connect_with_pool
7777+ ~sw
7878+ ~clock
7979+ ~on_message
8080+ ~on_disconnect
8181+ ~config
8282+ ~pool
8383+ ~endpoint
8484+ ()
8585+ in
8686+8787+ Logs.info (fun m -> m "Connected to MQTT broker");
8888+8989+ Mqtte_eio.Client.subscribe ~qos:`At_least_once [topic] client;
9090+ Logs.info (fun m -> m "Subscribed to %s" topic);
9191+9292+ Logs.info (fun m -> m "Listening for OwnTracks location updates...");
9393+ Logs.info (fun m -> m "(Press Ctrl+C to exit)");
9494+9595+ while Mqtte_eio.Client.is_connected client do
9696+ Eio.Time.sleep clock 1.0
9797+ done;
9898+9999+ Mqtte_eio.Client.disconnect client;
100100+ Logs.info (fun m -> m "Disconnected")
101101+102102+let term =
103103+ Term.(const run $ Mqtte_eio.Cmd.term $ topic)
104104+105105+let cmd =
106106+ let doc = "Subscribe to OwnTracks location messages over MQTT" in
107107+ let man = [
108108+ `S Manpage.s_description;
109109+ `P "Connects to an MQTT broker and subscribes to OwnTracks location \
110110+ messages, pretty-printing the received data.";
111111+ `S Manpage.s_examples;
112112+ `Pre " owntracks-subscriber -h broker.example.com -p 1883 -t 'owntracks/#'";
113113+ `Pre " owntracks-subscriber -h secure.example.com --tls -u user";
114114+ `Pre " MQTT_HOST=broker.example.com owntracks-subscriber";
115115+ `S Manpage.s_bugs;
116116+ `P "Report bugs at https://github.com/example/mqtt-eio/issues";
117117+ ] in
118118+ let info = Cmd.info "owntracks-subscriber" ~version:"0.1.0" ~doc ~man in
119119+ Cmd.v info term
120120+121121+let () = exit (Cmd.eval cmd)