0

I am developing mqtt web client for an IOT project using NextJs and mqtt package. In order to allow the client object to be shared among all components, I implemented a context API in which I defined some states as seen in the code below. The issue I am having here is, anytime I make update to msg state using setMsg function in the 'message' event handler, the msg does not get updated.

If I also try to publish a message by clicking a button, the message is not published. The only I was able to publish is by calling the client.publish intermittently inside setInterval

I am using the shiftr.io mqtt broker and I see an error stating that connection failed even though the shiftr.io dashboard indicated that connection is established by showing the client with its ID.

Thank you in advance.

** index.js file:**


import Car from '../components/Car';
import CarList from '../components/CarList';
import Board from '../components/Board';
import Notification from '../components/Notification';
import { useState, useEffect } from 'react';
import { useGlobalContext } from '../lib/context';
import mqtt from 'mqtt'
import Head from 'next/head'

export default function Home() {
  
  // console.log(JSON.parse(client).connected)
  const client = mqtt.connect('mqtt://tatwo:[email protected]', {
    clientId: 'client1'
  })

  const [freeSpace, setFreeState] = useState(1)
  const {setSpaceStatus, setMqttClient, mqttClient, setMsg, msg} = useGlobalContext()
  const [spaceMessageString, setSpaceMessageString] = useState(['0','0','0'])

  const publishStatus = (msg, clt)=>{
      client.publish('/reservation', msg)
  }

  if(client){
    setMqttClient(client)
  }

  client.on('connect', function(){
    console.log('connected')
    client.subscribe('space')
  })

  client.on('message', function(topic, message){
    console.log('receieved: ', message.toString().split(','))
    // setSpaceMessageString(message.toString().split(','))
    setMsg(message.toString())
    // setSpaceStatus(message.toString().split(','))
  })

  useEffect(() => {
    return ()=>{
        if(mqttClient){
          mqttClient.end()
        } 
    }

  }, [spaceMessageString])

   
  return (
    <div className='flex flex-col items-center justify-center'>
      <h1 className='text-white text-3xl md:text-5xl font-extrabold text-center'>Parking without stress</h1>
      <p className='text-amber-500 text-lg my-5'>Use smart parking system to check for parking space before you drive. </p>
      <Board />
      <p>{msg}: {mqttClient?.connected == true ? 'Onlined': 'offline'}</p>
      {
        freeSpace === 0 ?
        // <Notification /> : <CarList spaceMessageString={spaceMessageString} />
        <Notification /> : (
          <div className='grid grid-cols-1 md:grid-cols-3 gap-4 my-5 w-full'>
            {
              spaceMessageString.map((space, index)=>  
                <Car 
                  name={`Space ${index + 1}`} 
                  message={spaceMessageString[index]} 
                  key={index}
                  identity={index + 1}
                  publishStatus={publishStatus}
                />
              )
            }
        </div>
        )
      }
    </div>
  )

}

** context.js: **

import React from 'react'
import { createContext, useContext, useState } from 'react'

const AppContext = createContext({});

const AppProvider = ({children}) => {


    const [user, setUser] = useState(null)
    const [reservations, setReservations] = useState([])
    const [spaceStatus, setSpaceStatus] = useState([1, 0, 0])
    const [connected, setConnected] = useState(false)
    const [mqttClient, setMqttClient] = useState(null)
    const [msg, setMsg] = useState('no message')

    const client = null;

    return (
        <AppContext.Provider value={
            {
                user, 
                setUser, 
                spaceStatus, 
                setSpaceStatus,
                reservations,
                setReservations,
                connected, 
                setConnected,
                client,
                setMqttClient,
                mqttClient, 
                setMsg, 
                msg
            }
        }>
            {children}
        </AppContext.Provider>
    )
}

export const useGlobalContext = () => useContext(AppContext);

export default AppProvider

** _app.js: **

import Layout from '../components/Layout'
import '../styles/globals.css'
import AppProvider from '../lib/context';

export default function App({ Component, pageProps }) {
  return (
  
    <AppProvider>
      <Layout>
        <Component {...pageProps} />
      </Layout>
    </AppProvider>
  )
}

enter image description here

3
  • Please make sure you change the username and password now you have shared them with the whole internet. Also make sure that the broker you are connecting to support MQTT over WebSockets on port 80 as the ` mqtt://` connection is getting automatically converted to ws:// due to being run in the browser.
    – hardillb
    Commented Jan 2, 2023 at 13:52
  • The username and password are not the actual ones I use. Like you mentioned, I believe the broker does not support MQTT over websocket, because my Esp8266 microcontroller communicates well with the same broker via the same URL. Thank you, @hardillb Commented Jan 2, 2023 at 14:35
  • If the broker doesn't support MQTT over WS then this code will never connect (You can ONLY use MQTT over WebSockets from the web browser)
    – hardillb
    Commented Jan 2, 2023 at 14:37

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.