1

I have a few devices that produce data over MQTT sent to GCP IoT core. I want to monitor if the device is currently connected or disconnected from the MQTT broker. This was already answered elsewhere on SO and this is the approach I'm currently using: monitor Stackdriver logs for CONNECT/DISCONNECT messages and publish them to a separate Pub/Sub topic. This topic is then read by a Firebase Function to update my device online/offline field.

This works in theory, but due to the JWT expiration field, I am forced to re-connect my devices every time the token is expired, causing a lot of spurious online/offline triggers. Is there a way perhaps refresh the token while keeping the connection? Or a better approach to simply monitor connectivity of a device?

I can probably use the hearbeat event and only consider device being offline if no hearbeat was received within N amount of minutes, or even periodically sending some kind of ping command to the device. Although, it would be nice to simply know if device is currently connected or not.

alexm
  • 460
  • 5
  • 14
  • 1
    Additionally, creating a Stackdriver Sink into another PubSub topic would have been okay, but the order of these events is not guaranteed to be the same when it arrives at the firebase function. So I sometimes end up with status updated from online to online again, and then from online to offline. This looks almost impossible to handle this correctly. – alexm Aug 03 '20 at 12:15
  • I have come to the same exact solution and I am facing the same issue. Did you end up figuring out a better way to do this? – leonardo Jan 15 '21 at 08:36
  • 1
    @leonardo The first, pure MQTT solution: I eventually made a new pubsub topic called 'ping' and simply sent small packets to it from my device, recording it in my firebase as "lastPing" using cloud function subscribed to that 'ping' pubsub topic. Then ran a periodic function every N minutes to check if "lastPing" happened > X minutes ago. If it did, I'd consider device offline and sent notification to my users, offline->online state is reverse, but everyting is really messy. I will post a follow up in the answers. – alexm Jan 18 '21 at 04:41
  • Thanks for the advice, I am thinking of something similar. I can't really rely on Balena.io since I plan on having many more devices. However, since Google is already tracking this heartbeat, I will try to leverage that somehow and use a similar method of checking whether it was in the last N minutes. My concern then would be making it scalable; wouldn't want to check on pings from many devices in the future using the same function. – leonardo Jan 19 '21 at 09:08
  • @leonardo Yeah, balena way is not really an answer to this. That was also my concern exactly. One function checking lots of devices for "last heartbeat" is not ideal. Feel free to submit an answer to this post when you figure out something :) – alexm Jan 21 '21 at 06:36
  • I'll try, so far the heartbeat check is what might work for me. But there should be a more scalable way of doing it. – leonardo Jan 21 '21 at 14:58

2 Answers2

1

For a pure MQTT solution, what I was already doing, and what Orlandog suggested is correct, but doesn't solve the underlying problem of receiving DISCONNECT/CONNECT messages everytime a JWT token is refreshed. That's just how the protocol is supposed to work.

What I ended up with is using balena.io on my devices, which runs docker containers with my apps on balena OS, and the OS itself is connected through a VPN. So regardless of the MQTT state of my app I can use balena API to monitor device online state. This API is then polled using firebase cloud function.

To summarise:

  • IoT Core app sending/receiving MQTT with JWT refresh as a docker container
  • Balena OS with configured network, connected to Balena VPN
  • Balena API which lets you query device status
  • Cloud Function which calls balena API and stores values in Firebase

Balena is free up to 10 devices and they support a good range of hardware.

alexm
  • 460
  • 5
  • 14
0

I think that the way you are monitoring the devices through the implementation with Stackdriver logging and PubSub is the most appropriate.

At the same time, regarding to the expiration of the JWT token, I recommend you verify this documentation, it provides several examples of how to refresh the token and thus prevent devices from being disconnected.

Orlandog
  • 325
  • 1
  • 4
  • 1
    Thanks for the suggestion. I have no difficulties refreshing the JWT, but this does require a re-connect. In the doc you linked `client.disconnect(); client.connect();`. This behaviour produces DISCONNECT/CONNECT logs in the Stackdriver. It looks like there is no way to monitor online state continuously without JWT refresh interruptions. – alexm Aug 15 '20 at 09:21
  • What kind of actions are you trying to trigger with the connect and disconnect events? – Orlandog Aug 18 '20 at 23:32
  • 1
    Firebase Cloud Function listens to Pub/Sub topic `online`, Stackdriver publishes connection log messages to this topic. This cloud function then updates a boolean field in my database that indicates device online status. In turn, another functions is triggered based on this boolean field, which sends an email notification to the user if device goes offline/online. With JWT refresh, user gets erroneous notifications due to multiple MQTT disconnect/connect messages. I need a stable way to determine if device has gone offline due to network error or physical power down. – alexm Aug 29 '20 at 04:22