X button icon

Jasmine Nackash is a multidisciplinary designer and developer intereseted in creating unique and innovative experiences.

Week #09

Server problems & MQTT

I went to Tom's office hours to try and work out my server issues (the 404 thing). We removed some redundant files I had when I first set up a different domain name, and rechecked the server block configuration but it still didn't work. The weird thing was that we were seeing a 404 when we should have seen a 502. Time was up and Tom suggested I try removing the default folder from both sites-enabled and sites-available, and if that doesn't work then to also break the symbolic link between the two directories (that I initially set up when installing nginx).

So I got to it:

this was a bit scary but I made sure to make a copy of its content before deleting it

I removed the default file from both folders and still got a 404. I then proceeded to remove the symbolic link through sites-enabeld, which resulted in... not even a 404:

Which is when I decided to relink them. But I also had another idea — I remembered there was a command for checking for errors:

Finally new information! I went back into the server block and realized I had double server{} blocks! (this is certbot's doing!!!)

So I took the important bits (important = unique. The other stuff already exists in the first block) and put them in the first block and removed the second block as follows:

Confirmed that the conflict was resolved:

And restarted nginx only to see this:

But this was actually helpful — I know 301 is a redirect so I figure, well, this is because of those two lines of code from certbot that return 301s. So I removed them too...

...Which still resulted in a 404 until I realized I should be looking at the proxy address and viola!

I never thought I would be this happy to see a 502

...And then I started the node server:

Finally!

(I do wonder if it was ok to remove everything I removed though but I guess I can figure out redirection when I need it).

MQTT

I started by installing shiftr.io and MQTT Explorer, registered accounts and deployed an instance. I used the MQTT Explorer to subscribe and publish a topic as an example to verify that it works:

I want to use MQTT in my Project Development Studio project titled The Red Line, so this is a good opportunity to figure that part out. Most of the project's functionalities run server side through Firebase Functions, the Arduino being the last point in the pipeline — I want to eventually send data from the server to the Arduino. It seems like the WiFiSimpleReceive example from the ArduinoMqttClient library should do pretty much just that.

I installed the mqtt package in my server folder. While looking at how to publish the message from the server I stumbled upon something called QoS — Quality of Service, that I've seen included in examples of how to subscribe and publish. Apparently there are three levels of QoS:

  • QoS 0 ({ qos: 0 }) - "At most once" delivery: pretty much "fire and forget", there's no guarantee of delivery, is the fastest option but the message might get lost.
  • QoS 1 ({ qos: 1 }) - "At least once" delivery: guaranteed delivery, might be delivered multiple times, requires "acknowledgement" (the broker must tell the sender that it received the message. This happens automatically but if the "got it" message gets lost then the sender will send the message again to the broker, which is why you might see multiple messages).
  • QoS 2 ({ qos: 2 }) - "Exactly once" delivery: guaranteed delivery, high overhead, slowest option but most reliable.
  • In my case I do need a guaranteed delivery, but I don't really care that much about speed. I'm also ok with sending the message multiple times — it's just a number used to calculate how much the motor should rotate, so if it's the same number again it just won't rotate. So I guess I'm going with { qos: 1 }.

    The code is basically this:

    const mqtt = require('mqtt');

    const MQTT_BROKER_URL = "theredline.cloud.shiftr.io";

    const MQTT_USERNAME = "theredline";

    const MQTT_PASSWORD = "[OMITTED]";

    const MQTT_TOPIC = "mainScore";

    const client = mqtt.connect(MQTT_BROKER_URL, {

     username: MQTT_USERNAME,

     password: MQTT_PASSWORD

    });

    client.on('connect', () => {

     console.log('Connected to MQTT broker');

     client.subscribe(MQTT_TOPIC, { qos: 1 }, (err) => {

       if (err) console.error('Failed to subscribe to topic:', err);

     });

    });

    client.on('error', (err) => {

     console.error('MQTT error:', err);

    });

    and then in the function where I update the Firebase realtime database I also publish to the client:

    async function updateMainScore(weightedAverage) {

     const mainScoreRef = admin.database().ref('mainScore');

     await mainScoreRef.set({ score: weightedAverage });

     console.log("Main score updated successfully.");

     if (client.connected) {

       const scoreMessage = JSON.stringify({ score: weightedAverage });

       client.publish(MQTT_TOPIC, scoreMessage, { qos: 1 }, (err) => {

         if (err) {

           console.error('Failed to publish message:', err);

         } else {

           console.log(`Published score to MQTT topic "${MQTT_TOPIC}":`, scoreMessage);

         }

       });

     }

    }

    I also added some client side functionalities to make it easier to test and debug. The web client connection worked:

    And then I went on to also connect the Arduino:

    And I could see the network nodes in shiftr.io:

    Eventually the number that the Arduino receives would go to a function that calculates the degrees for a stepper motor. I kept having the shiftr.io shut on me and say it would go back up in 50 minutes or so:

    So I hope this will work for my actual project... I guess I'll time the connections to connect, receive / send data and disconnect so that I wouldn't go over the 6 hour limit. I really only need to send one message every few minutes or so, so if I manage it correctly it shouldn't be a problem. I can use the WatchdogTimer library to have the Arduino sleep in between and just get new the latest score when it wakes up. But this might need to somehow be coordinated with the server side connection. I'll report back on this!