ctucx.git: departures2mqtt

Export bus departures[kvg-kiel] to MQTT

commit 41a0e352cc99ccfb918af7a5316842fb37b1fd4f
Author: Leah (ctucx) <git@ctu.cx>
Date: Tue, 13 Dec 2022 14:21:28 +0100

initial commit
5 files changed, 211 insertions(+), 0 deletions(-)
A
departures2mqtt.nimble
|
13
+++++++++++++
A
flake.lock
|
43
+++++++++++++++++++++++++++++++++++++++++++
A
flake.nix
|
55
+++++++++++++++++++++++++++++++++++++++++++++++++++++++
A
nim.cfg
|
1
+
A
src/departures2mqtt.nim
|
99
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
diff --git a/departures2mqtt.nimble b/departures2mqtt.nimble
@@ -0,0 +1,13 @@
+# Package
+
+version       = "0.1.0"
+author        = "Leah (ctucx)"
+description   = "Send kvg-kiel bus departures to mqtt"
+license       = "MIT"
+srcDir        = "src"
+bin           = @["departures2mqtt"]
+
+
+# Dependencies
+
+requires "nim >= 1.4.8"
diff --git a/flake.lock b/flake.lock
@@ -0,0 +1,43 @@
+{
+  "nodes": {
+    "flake-utils": {
+      "locked": {
+        "lastModified": 1667395993,
+        "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=",
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f",
+        "type": "github"
+      },
+      "original": {
+        "owner": "numtide",
+        "repo": "flake-utils",
+        "type": "github"
+      }
+    },
+    "nixpkgs": {
+      "locked": {
+        "lastModified": 1670772952,
+        "narHash": "sha256-b7V3cGtMNcQ5c6hwRqqX+eIuNUj+O3orsb64BKPR9yc=",
+        "owner": "NixOS",
+        "repo": "nixpkgs",
+        "rev": "dfef2e61107dc19c211ead99a5a61374ad8317f4",
+        "type": "github"
+      },
+      "original": {
+        "owner": "NixOS",
+        "ref": "nixos-22.11",
+        "repo": "nixpkgs",
+        "type": "github"
+      }
+    },
+    "root": {
+      "inputs": {
+        "flake-utils": "flake-utils",
+        "nixpkgs": "nixpkgs"
+      }
+    }
+  },
+  "root": "root",
+  "version": 7
+}
diff --git a/flake.nix b/flake.nix
@@ -0,0 +1,54 @@
+{
+  description = "Send kvg-kiel bus departures to mqtt";
+
+  inputs = {
+    flake-utils.url = "github:numtide/flake-utils";
+    nixpkgs.url     = "github:NixOS/nixpkgs/nixos-22.11";
+  };
+
+  outputs = { self, nixpkgs, flake-utils }: {
+
+    overlay = final: prev: {
+
+      departures2mqtt = (
+        let
+          nmqtt = final.fetchFromGitHub {
+            owner  = "zevv";
+            repo   = "nmqtt";
+            rev    = "v1.0.4";
+            sha256 = "1by0xyqz754dny19lf8rpkg42passnj0rs6rk3jr763m1zr803mc";
+          };
+
+        in final.nimPackages.buildNimPackage {
+          name        = "departures2mqtt";
+          src         = self;
+
+          buildInputs = [ nmqtt ];
+
+          nimBinOnly  = true;
+          nimRelease  = true;
+        }
+      );
+
+    };
+
+  } // (flake-utils.lib.eachDefaultSystem (system:
+    let
+      pkgs = import nixpkgs {
+        inherit system;
+        overlays = [ self.overlay ];
+      };
+
+    in rec {
+
+      packages.default         = pkgs.departures2mqtt;
+      packages.departures2mqtt = pkgs.departures2mqtt;
+
+      apps.default = {
+        type = "app";
+        program = "${pkgs.departures2mqtt}/bin/departures2mqtt";
+      };
+
+    }
+  ));
+}+
\ No newline at end of file
diff --git a/nim.cfg b/nim.cfg
@@ -0,0 +1 @@
+-d:ssl
diff --git a/src/departures2mqtt.nim b/src/departures2mqtt.nim
@@ -0,0 +1,99 @@
+import std/asyncdispatch
+import std/[strutils, strtabs]
+import std/[os, parseopt, httpclient]
+import std/[json, times]
+
+import nmqtt
+
+var p        = initOptParser(commandLineParams())
+var stations : seq[string]
+var host     : string
+var port     : int
+var user     : string
+var pass     : string
+var topic    : string
+
+while true:
+  p.next()
+  case p.kind
+  of cmdEnd: break
+  of cmdArgument: break
+  of cmdShortOption, cmdLongOption:
+    case p.key:
+      of "stations":
+        if p.val == "":
+          quit("option 'stations' can't be empty!", 1)
+        else:
+          stations = p.val.split(",")
+      of "mqtt-host":
+        if p.val == "":
+          quit("option 'mqtt-host' can't be empty!", 1)
+        else:
+          host = p.val
+      of "mqtt-port":
+        if p.val == "":
+          quit("option 'mqtt-port' can't be empty!", 1)
+        else:
+          port = p.val.parseInt
+      of "mqtt-user":
+        if p.val == "":
+          quit("option 'mqtt-user' can't be empty!", 1)
+        else:
+          user = p.val
+      of "mqtt-pass":
+        if p.val == "":
+          quit("option 'mqtt-pass' can't be empty!", 1)
+        else:
+          pass = p.val
+      of "mqtt-topic":
+        if p.val == "":
+          quit("option 'mqtt-topic' can't be empty!", 1)
+        else:
+          topic = p.val
+      else:
+        quit("unknown option: '" & $p.key & "'", 1)
+
+
+if (stations.len == 0):
+  quit("You need to specify at least one station!", 1)
+
+if (host == ""):
+  quit("You need to specify an mqtt-host!", 1)
+
+if (port == 0):
+  port = 1883
+
+if (topic == ""):
+  quit("You need to specify a mqtt-topic!", 1)
+
+
+let client = newHttpClient()
+var data   = newJObject()
+data.add("lastUpdated", newJInt(getTime().toUnix()))
+data.add("departures", newJObject())
+
+for id in stations:
+  let jsonData   = parseJson(client.getContent("https://www.kvg-kiel.de/internetservice/services/passageInfo/stopPassages/stop?stop=" & $id & "&mode=departure&language=en"))
+  var departures = newJArray()
+
+  for entry in jsonData{"actual"}:
+    departures.add(%* {
+      "line":         entry{"patternText"},
+      "direction":    entry{"direction"},
+      "departure_in": entry{"mixedTime"}.getStr.replace(" %UNIT_MIN%", "")
+    })
+
+  data["departures"].add(jsonData{"stopName"}.getStr, departures)
+
+let mqtt = newMqttCtx("departures2mqtt")
+mqtt.set_verbosity(1)
+mqtt.set_host(host, port)
+
+if (user != "" and pass != ""):
+  mqtt.set_auth(user, pass)
+
+waitFor mqtt.connect()
+waitFor sleepAsync 500
+waitFor mqtt.publish(topic, $data, 2, true)
+waitFor sleepAsync 500
+waitFor mqtt.disconnect()