Trouble Connecting to Google Cloud IoT via MQTT with Node.js

859 views Asked by At

I'm trying to create a MQTT client that'll connect to the Google Cloud IoT Core, but for some reason, it won't connect at all. Here's what I have so far

mqtt = require("mqtt")
fs = require("fs")
var jwt = require('jsonwebtoken');


const projectId = "my-project" 
const deviceId = "my-device" 
const registryId = "my-degistry" 
const region = "us-central1"
const algorithm = "RS256"
const privateKeyFile = "./rsa_private.pem"
const mqttBridgeHostname = "mqtt.googleapis.com"
const mqttBridgePort = 8883
const messageType = "events"

//The mqttClientId is a unique string that identifies a particular device. 
//For Google Cloud IoT Core, it must be the format below
const mqttClientId = `projects/${projectId}/locations/${region}/registries/${registryId}/devices/${deviceId}`
const mqttTopic = `/devices/${deviceId}/${messageType}`;


const createJwt = (projectId, privateKeyFile, algorithm) => {
    // Create a JWT to authenticate this device. The device will be disconnected
    // after the token expires, and will have to reconnect with a new token. The
    // audience field should always be set to the GCP project id.
    const token = {
      iat: parseInt(Date.now() / 1000),
      exp: parseInt(Date.now() / 1000) + 20 * 60, // 20 minutes
      aud: projectId,
    };
    const privateKey = fs.readFileSync(privateKeyFile);
    return jwt.sign(token, privateKey, {algorithm: algorithm});
  };

//Username field is ignored in Cloud IoT Core, but it must be set to something
//Password field sends a JWT (javascript web token) to authorize the device
//mqtts protocol causes library to connecti using SSL, which is required for IoT Core
const connectionArgs = {
    host: mqttBridgeHostname,
    port: mqttBridgePort,
    clientId: mqttClientId,
    username: "unused",
    password: createJwt(projectId, privateKeyFile, algorithm),
    protocol: "mqtts",
    secureProtocol: "TLSv1_2_method"
}

const client = mqtt.connect(connectionArgs)

client.on("connect", (connected)=>{
    console.log("Attempting to connect")
    if (!connected) {
        console.log("Client failed to connect")
    } else {
        console.log("Client is connected!")
    }
})

client.on("error", err => {
    console.log(err)
    setTimeout(( ()=> {  
        console.log('Terminating process')
        return process.kill(process.pid);
    }), 1000);
})

client.on("packetsend", (payload) => {
    console.log("Payload has been sent")
    return process.kill(process.pid)
})

client.on("packetreceive", packet => {
    console.log("Killing")
    //return process.kill(process.pid)
})

client.on("reconnect", ()=>{
    console.log("Attempting a reconnect")
    //return process.kill(process.pid)
})

client.on("close", ()=>{
    console.log("A disconnect occurred")
    // return process.kill(process.pid)
})

client.on("offline", () => {
    console.log("Client is offline")
    //return process.kill(process.pid)
})

I'm not getting any errors when I try to connect to the server. In other words, everything seems to be authenticating properly and I get no error messages, but the client never connects to the Cloud and instead repeatedly tries to reconnect in an endless cycle (which is why I included code to kill the script). I tried going through the Google Cloud troubleshooting page but nothing there really seemed to help. I don't get any sort of errors messages or helpful tidbits of information when using the Cloud SDK like the guide suggested.

I've opened up the port 8883 through my firewall just in case that was the issue but it doesn't appear to be.

I based this code off some of Google's guides and based on this guide here. I have a registry, project, and device all set up with a proper RSA key.

So I'm not really sure how to proceed! If there's any additional information that would help, please let me know.

Thank you.

2

There are 2 answers

0
DavicC On BEST ANSWER

Apart from the links I provided in the comment section and as additional to what you have found out, some users use the Project Number instead of the Project ID which leads to a similar concern which you have encountered. It really pays to double check everything in your configuration as you troubleshoot.

If you need to have a refresher about the authentication, you may also refer to this link.

0
Alex Snyder On

I realized that when I was creating the project and registry on the Google Console, I actually mistyped the name I was intending (I thought it was "testmqtt" but it was actually "tesmqtt").

So if you're having an issue similar to this, I'd suggest trying the follwing:

  • Make sure your you've spelled everything right. Make sure the project title is correct, the registry title, etc. It sounds dumb but these types of mistakes happen, so it doesn't hurt to check them first. Otherwise you'll overthink things like I did.
  • Check out this this page for troubleshooting. There's two parts of this troubleshooting page that might really help you. The first is trying to see if you can actually connect to the cloud at all. You can test if you're able to make a connection by issuing a command like openssl s_client -connect mqtt.googleapis.com:8883 on the command line. You'll need to have openssl downloaded in order to issue that command, however. You can see the page I just linked for more details about testing your connection. The second thing you can do is check to see if you have authentication by running a gcloud command using Google's sdk. The troubleshooting page I linked also has more details in this regard.
  • This quickstart guide is also particularly helpful. It might be confusing to navigate at first but understanding it will be your best bet.
  • Google's github repository also has some good examples of how to make an mqtt connection to the cloud IoT core.

DavidC in the comments below helped me find some of these helpful links, so credit should go to him.