From 5fc8d487327a3f722825b7fd95802b3342523fc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20K=C3=B6nig?= <52958977+smaktacular@users.noreply.github.com> Date: Wed, 6 Jan 2021 18:06:56 +0100 Subject: [PATCH] Added with-mqtt-js example (#17939) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Added with-mqtt-js example * Fixed eslint/prettier errors * Update README.md * Updated with-mqtt-js to latest next/react versions, WIP: Refactoring useMqtt() * A2PC * Working example, unrefactored * A2PC * Ran prettier * Used NEXT_PUBLIC_ prefix instead of keys as props * Updated readme and added .env.local.example Co-authored-by: Sebastian König Co-authored-by: Luis Alvarez D --- examples/with-mqtt-js/.env.local.example | 4 ++ examples/with-mqtt-js/README.md | 34 +++++++++++++ examples/with-mqtt-js/lib/useMqtt.js | 55 +++++++++++++++++++++ examples/with-mqtt-js/package.json | 16 ++++++ examples/with-mqtt-js/pages/index.js | 62 ++++++++++++++++++++++++ 5 files changed, 171 insertions(+) create mode 100644 examples/with-mqtt-js/.env.local.example create mode 100644 examples/with-mqtt-js/README.md create mode 100644 examples/with-mqtt-js/lib/useMqtt.js create mode 100644 examples/with-mqtt-js/package.json create mode 100644 examples/with-mqtt-js/pages/index.js diff --git a/examples/with-mqtt-js/.env.local.example b/examples/with-mqtt-js/.env.local.example new file mode 100644 index 0000000000..c24f041b01 --- /dev/null +++ b/examples/with-mqtt-js/.env.local.example @@ -0,0 +1,4 @@ +NEXT_MQTT_URI="wss://test.mosquitto.org:8081/mqtt" +NEXT_MQTT_CLIENTID="a_client_id" +NEXT_MQTT_USERNAME="username" +CONTENTFUL_PREVIEW_SECRET="a_secure_password" \ No newline at end of file diff --git a/examples/with-mqtt-js/README.md b/examples/with-mqtt-js/README.md new file mode 100644 index 0000000000..4dc2938226 --- /dev/null +++ b/examples/with-mqtt-js/README.md @@ -0,0 +1,34 @@ +# MQTT Client example + +This example shows how to use [MQTT.js](https://github.com/mqttjs/MQTT.js) with Next.js. + +## Deploy your own + +Deploy the example using [Vercel](https://vercel.com): + +[![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/import/project?template=https://github.com/vercel/next.js/tree/canary/examples/with-mqtt-js) + +## How to use + +Execute [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) with [npm](https://docs.npmjs.com/cli/init) or [Yarn](https://yarnpkg.com/lang/en/docs/cli/create/) to bootstrap the example: + +```bash +npx create-next-app --example with-mqtt-js with-mqtt-js-app +# or +yarn create-next-app --example with-mqtt-js with-mqtt-js-app +``` + +To set up a connection URI with a mqtt client, copy the `.env.local.example` file in this directory to `.env.local` (which will be ignored by Git): + +```bash +cp .env.local.example .env.local +``` + +Then set each variable on `.env.local`: + +- `NEXT_MQTT_URI`: The URI of the broker. For example `wss://test.mosquitto.org:8081/mqtt` +- `NEXT_MQTT_CLIENTID`: An arbritrary string of max. 23 characters. +- `NEXT_MQTT_USERNAME`: The username for the connection to the broker. +- `NEXT_MQTT_PASSWORD`: The password for the connection to the broker. + +Deploy it to the cloud with [Vercel](https://vercel.com/import?filter=next.js&utm_source=github&utm_medium=readme&utm_campaign=next-example) ([Documentation](https://nextjs.org/docs/deployment)). diff --git a/examples/with-mqtt-js/lib/useMqtt.js b/examples/with-mqtt-js/lib/useMqtt.js new file mode 100644 index 0000000000..973fab6059 --- /dev/null +++ b/examples/with-mqtt-js/lib/useMqtt.js @@ -0,0 +1,55 @@ +import MQTT from 'mqtt' +import { useEffect, useRef } from 'react' + +function useMqtt({ + uri, + options = {}, + topicHandlers = [{ topic: '', handler: ({ topic, payload, packet }) => {} }], + onConnectedHandler = (client) => {}, +}) { + const clientRef = useRef(null) + + useEffect(() => { + if (clientRef.current) return + if (!topicHandlers || topicHandlers.length === 0) return () => {} + + try { + clientRef.current = options + ? MQTT.connect(uri, options) + : MQTT.connect(uri) + } catch (error) { + console.error('error', error) + } + + const client = clientRef.current + topicHandlers.forEach((th) => { + client.subscribe(th.topic) + }) + client.on('message', (topic, rawPayload, packet) => { + const th = topicHandlers.find((t) => t.topic === topic) + let payload + try { + payload = JSON.parse(rawPayload) + } catch { + payload = rawPayload + } + if (th) th.handler({ topic, payload, packet }) + }) + + client.on('connect', () => { + if (onConnectedHandler) onConnectedHandler(client) + }) + + return () => { + if (client) { + topicHandlers.forEach((th) => { + client.unsubscribe(th.topic) + }) + client.end() + } + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []) +} + +export default useMqtt diff --git a/examples/with-mqtt-js/package.json b/examples/with-mqtt-js/package.json new file mode 100644 index 0000000000..3997c7d484 --- /dev/null +++ b/examples/with-mqtt-js/package.json @@ -0,0 +1,16 @@ +{ + "name": "with-mqtt-js", + "version": "1.0.0", + "scripts": { + "dev": "next", + "build": "next build", + "start": "next start" + }, + "dependencies": { + "mqtt": "4.2.6", + "next": "latest", + "react": "17.0.1", + "react-dom": "17.0.1" + }, + "license": "MIT" +} diff --git a/examples/with-mqtt-js/pages/index.js b/examples/with-mqtt-js/pages/index.js new file mode 100644 index 0000000000..6de3eedd33 --- /dev/null +++ b/examples/with-mqtt-js/pages/index.js @@ -0,0 +1,62 @@ +import { useState, useRef } from 'react' +import useMqtt from '../lib/useMqtt' + +export default function Home() { + const [incommingMessages, setIncommingMessages] = useState([]) + const addMessage = (message) => { + setIncommingMessages((incommingMessages) => [...incommingMessages, message]) + } + const clearMessages = () => { + setIncommingMessages(() => []) + } + + const incommingMessageHandlers = useRef([ + { + topic: 'topic1', + handler: (msg) => { + addMessage(msg) + }, + }, + ]) + + const mqttClientRef = useRef(null) + const setMqttClient = (client) => { + mqttClientRef.current = client + } + useMqtt({ + uri: process.env.NEXT_PUBLIC_MQTT_URI, + options: { + username: process.env.NEXT_PUBLIC_MQTT_USERNAME, + password: process.env.NEXT_PUBLIC_MQTT_PASSWORD, + clientId: process.env.NEXT_PUBLIC_MQTT_CLIENTID, + }, + topicHandlers: incommingMessageHandlers.current, + onConnectedHandler: (client) => setMqttClient(client), + }) + + const publishMessages = (client) => { + if (!client) { + console.log('(publishMessages) Cannot publish, mqttClient: ', client) + return + } + + client.publish('topic1', '1st message from component') + } + + return ( +
+

Subscribed Topics

+ {incommingMessageHandlers.current.map((i) => ( +

{i.topic}

+ ))} +

Incomming Messages:

+ {incommingMessages.map((m) => ( +

{m.payload.toString()}

+ ))} + + +
+ ) +} -- GitLab