MQTT CAN Gateway


I mentioned in an earlier post that my CAN Input modules now supported analog input mode on the first 8 inputs. I showed how I could use these analog inputs with NTC temperature sensors to take readings on a wired network rather than wireless.

The next step was to write a gateway that would take these analog readings off the CAN bus and send them to MQTT in order for the existing perl script to pick them up and mash them into RRD databases – as it already does for the radio sensor data.

Other earlier posts provided some details and results while writing the SMS MQTT gateway. Its no surprise I mostly just copied the code for that interface and used it as a starting point.

The only major changes were

  • Removing the SMS specific code and replacing it with the CAN device equivalent.
  • Adding publish ability to my MqttDataProvider class
  • Hard coded decoding of CAN messages into MQTT topics/content publish calls inside this interface. The topic used is in this case is “/sensors/can/<bus id>/<id>/temperature”

In theory (perhaps I’ll do this later) this gateway should just publish all incoming messages into a single topic (e.g. “/messages/can/incoming”) that other “decoder” applications can subscribe to, decode any messages they know how to and then publish new messages to new topics (e.g. “/sensors/can/1/1/temperature”). 


Anyway, with those changes done its time to test. Here we see log showing CAN interface messages coming in.


Following each CAN messages we see an MQTT publish success – in this case there have been 21,100+ published messages since start up.


So CAN to MQTT is publishing, but how can we see the data – easy enough. The old perl script just needed a new subscribe string to take into account the data coming from can and radio, so here it is. Notice the “+/+/+” replacing the old “radio/+/+”

I still have to maunally create the RRD databases and add the extra graph generation script entries but its working.

The infrastructure needed to get CAN messages into MQTT is working, ready for something perhaps a bit more useful.



Wireless Problems vs Wired Alternatives

Wireless Problems

Anyone looking at my sensor data will notice that there are a lot of gaps where data has not been recorded. It’s was hard to know exactly what the issue is as the Arduino is running headless. If I see the data has stopped I just rebooted the Arduino by unplugging the USB and plugging it back it. Yes it fixes the problem but it is not a real solution.

I ran it locally the other day and noticed that it was stuck in a loop thinking it had received a new message, but of invalid type, over and over again. I didn’t catch the moment of transition from normal operation to error, maybe another logged test next time. Anyways it was just printing this

All the type numbers seemed random. Here is the code snippet. Nothing looks like it should cause a a problem. And the problem occurs at random times after reboot. Maybe a problem with the nRF library perhaps.

Update – I got tired of trying to find the problem so I changed the code to force a software reset when the unknown type message was detected.

 Wired Alternatives

In a previous post I went through all the iterations of a CAN Input Module design. The latest design includes 8 analog input channels. The inputs can be left floating or internally biased with 10K resistors to GND or VCC.

Input Schematic

That’s handy because if I use the internal 10K pull up I get the same circuit I use in the Arduino sensors. Time to test that theory. I’m using the first three inputs, set the channel IDs (1, 2, 3), set them to analog mode, and added a delay of 10 seconds.

Input Module Programming

With this setup (and the current firmware) I get a new analog reading for each channel at most once every 10 seconds – if the reading has actually changed. The delay is really to stop a deluge of data. The PIC has a 12 bit A2D so the readings range from 0 to 4095. The firmware does 32 sample averaging.

The device programmer software has a logging mode so I have extended the logging to print the analog reading and convert it to a temperature. Here are the logging results – slightly verbose but you get the idea. The sensors are all withing a few centimeters of each other and the values returned seem to be within spec for components I’m using.

  • The 10K bias resistors are probably +/- 5%
  • Channel 1 is a small NTC resistor from Element 14.
  • Channel 2 & 3 are cheapy Aliexpress sensors.

Logging Results

Those paying attention will note that my anticipated 10 second delay seems to evaluate to only 8 seconds … oops … the RTC timer based code in the PIC is probably running a tad too fast.

I have had this running for the last week, logging away, all is good.

CAN/MQTT Gateway

Next step is to write a CAN/MQTT gateway application. My CAN bus is accessed via a CAN to USB device so it should be a simple matter of writing some code to open a connection to the CAN bus, wait for incoming CAN messages and publish a message to an MQTT topic, similar to what the wireless sensors do.

This will also serve as a foundation for working in the opposite direction, subscribing to an MQTT topic, receiving messages and sending them out via CAN.

(more to come)