5.8 KiB


The "usual" (well, mine anyway) small sensor network layout using jeenodes:

{{jeenode sensor(s)...}} <~~[radio]~~>

  <~~> {{jeenode gateway}} <--UART-->

      /--------------- computer ---------------\
  <-->|{ser2net}  <--TCP--> {jeethru} <-> .... |

The aim of this project is to provide a single binary daemon, which listens on a TCP port (with the expectation of incoming jeenode gateway messages), processes them (i.e. decodes the RF12demo-formatted messages into meaningful sensor data), and then pushes them further. The output options are:

  • Another TCP port. This works as a simple forwarder, i.e. no decoding is done and the incoming messages are just relayed further. This relaying actually works both ways (i.e. also towards the jeenode gateway). However this daemon accepts more than one simultaneous connection (so it can act as a multiplexer for ser2net, which is usually used to relay the UART/serial messages from the gateway to/from TCP).
  • Plain CSV files (one line per reading, one file per type).
  • Publish MQTT messages (this is also potentially two-way, but the "to gateway" direction is not implemented yet).
  • Insert into MongoDB database.
  • (MongoDB and MQTT support is currently untested: a forced lib update may have introduced problems with this. Sorry.)

This program is written in rust, which is excellent in producing single static binaries which can be just copied around; and it is also very simple to cross-compile (e.g. using this docker setup, I compile on my laptop and just copy the resulting binary to my pocket beagle). Alternatively, to build a static x86_64 executable against musl, use cargo build --release --target=x86_64-unknown-linux-musl.

One drawback is that the "decoding the gateway messages" bit is semi-hardcoded into the program (see and source files), so if anyone wants to use this, they will need to have a look at the code and modify for their own sensor types/devices.

However, once the appropriate device types are hardcoded, the actual list of devices is configurable at runtime via the configuration file.

I wrote this program primarily for myself and my own small sensor network (and as a thing for learning rust), and I have no illusions about anyone else using this ;) So hardcoding the sensor types was good enough for me. Also, because of the brutal ease of cross-compiling and having a single binary daemon with no dependencies, I do not feel compelled to implement some complicated sensordata configuration system.


Various parameters can be configured when the program is run, in one of the three-and-a-half ways, listed here in decreasing order of priority (i.e. the top ones override the bottom ones):

  • Command line parameters: run jeethru -h to get the full list with short descriptions and defaults.
  • Environment variables: the possibilities and the format are the same as above, the variable names have the format JEETHRU_[OPT], where [OPT] is capitalised full name of a command line parameter. For example JEETHRU_HOST_MQTT=
  • Configuration file: the default name is jee_config.yml (this is possible to override with a command line parameter). It is in YAML format, and the possibilities and format are the same as above.
  • Defaults: hardcoded into the binary.

There are a few exceptions to this scheme:

  • Logging verbosity: only settable as a command line parameter (the more -v's appear, the more verbose the program is).
  • Configuration file path/name: only settable as a command line parameter.
  • Device list: only settable in the configuration file. See the supplied jee_config.yml for the expected format. This also means that if the configuration file is missing, no devices will be configured, and so effectively no message decoding will happen (however the rest of the features will work, so e.g. one-to-many port multiplexing, or publishing raw messages to MQTT).
  • And one quirk: The toggle_* switches toggle some feature (e.g. publishing to MQTT broker); all of these features are disabled by default. These are evaluated as follows: cmdline_switch XOR (env_var OVERRIDES cfg_file). (An example: If cmdline_switch is set, env_var is not present and it is set in cfg_file, the feature ends up disabled.)

miscellaneous operational details

The program panics/errors out in some cases and does not in some others. In particular:

  • If binding to any of the ports (incoming, outgoing) fails on startup, the program ends.
  • The program ends "naturally" when the incoming port closes.
  • If MongoDB is enabled and the connection to the database and/or posting a record to it fails, the whole program panics.
  • If writing to csv is enabled and writing to a file fails, the whole program panics.
  • If MQTT is enabled and the initial connection to the server fails, the program fails; however a failure of an individual publish message is only logged and the program continues.
  • If decoding of an incoming message (from the gateway) fails at any point (e.g. "not-a-message", "not-enough-bytes", "corrupted-data"), it is simply logged and ignored further.

cross compilation

As of 2023-04-21T15:21:55, I am cross compiling with cross-rs. It's configured in Cross.toml. Still uses docker so it should be running (and have a gig of space for the cross compile images available), but then cross build --release should do the job.


The project is licensed under MIT license.