npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

Iโ€™ve always been into building performant and accessible sites, but lately Iโ€™ve been taking it extremely seriously. So much so that Iโ€™ve been building a tool to help me optimize and monitor the sites that I build to make sure that Iโ€™m making an attempt to offer the best experience to those who visit them. If youโ€™re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, ๐Ÿ‘‹, Iโ€™m Ryan Hefnerย  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If youโ€™re interested in other things Iโ€™m working on, follow me on Twitter or check out the open source projects Iโ€™ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soonโ€“ish.

Open Software & Tools

This site wouldnโ€™t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you ๐Ÿ™

ยฉ 2025 โ€“ย Pkg Stats / Ryan Hefner

await-mqtt

v0.2.5

Published

๐Ÿ”„ Promise-based async/await wrapper for MQTT.js with React hooks

Readme

await-mqtt

๐Ÿ”„ Elegant Promise-based async/await wrapper for MQTT.js with TypeScript support and React hooks

Features

  • Promise-based API: Full Promise support for all MQTT operations
  • Async/Await Syntax: Clean, modern JavaScript with exception handling
  • TypeScript Ready: Comprehensive type definitions included
  • React Hooks: Easy integration with React applications
  • Smart Message Handling: Topic filtering with wildcard support
  • JSON Support: Automatic serialization for object messages
  • Timeout Control: Configurable timeouts for all operations
  • Connection Management: Auto-reconnect with configurable options
  • Simple Architecture: Straightforward integration with minimal setup
  • Lightweight: Minimal overhead on top of MQTT.js
  • Bun Optimized: Built with performance in mind

Installation

# Using npm
npm install await-mqtt mqtt

# Using yarn
yarn add await-mqtt mqtt

# Using bun
bun add await-mqtt mqtt

# If using with React
npm install await-mqtt mqtt react

Quick Start

Standard Usage

import { Mqtt } from 'await-mqtt';

async function main() {
  // Create a client and connect in one step
  const mqtt = await Mqtt({
    url: 'mqtt://broker.example.com',
    clientId: 'my-client',
  });

  try {
    console.log('Connected successfully!');

    // Subscribe to topics
    await mqtt.subscribe('sensors/#');

    // Register message handler with async support
    mqtt.onMessage('sensors/temperature', async (topic, message) => {
      const temperature = parseFloat(message.toString());
      console.log(`Temperature: ${temperature}ยฐC`);

      // Perform async operations inside handlers
      await processTemperature(temperature);
    });

    // Publish string message
    await mqtt.publish('sensors/command', 'READ');

    // Publish JSON object (automatically serialized)
    await mqtt.publish('sensors/config', {
      interval: 5000,
      precision: 2,
      enabled: true
    });

    // Clean disconnect when done
    await mqtt.end();
  } catch (err) {
    console.error('MQTT Error:', err);
  }
}

main();

React Hooks Usage

import React, { useState } from 'react';
import { MqttProvider, useMqtt, usePublish, useMessages } from 'await-mqtt/react';

// Main component with MQTT provider
function App() {
  return (
    <MqttProvider options={{ clientId: 'react-client' }}>
      <div className="app">
        <h1>MQTT React Demo</h1>
        <ConnectionControl />
        <MessagePublisher />
        <MessageSubscriber />
      </div>
    </MqttProvider>
  );
}

// Connection control component
function ConnectionControl() {
  const { connect, disconnect, isConnected, isConnecting, error } = useMqtt();
  const [brokerUrl, setBrokerUrl] = useState('ws://broker.example.com:8883');

  return (
    <div>
      <h2>Connection Status: {isConnected ? 'Connected' : (isConnecting ? 'Connecting...' : 'Disconnected')}</h2>
      {error && <p className="error">Error: {error.message}</p>}

      <input 
        type="text" 
        value={brokerUrl} 
        onChange={(e) => setBrokerUrl(e.target.value)} 
        placeholder="Broker URL"
      />

      <button onClick={() => isConnected ? disconnect() : connect(brokerUrl)}>
        {isConnected ? 'Disconnect' : 'Connect'}
      </button>
    </div>
  );
}

// Message publisher component
function MessagePublisher() {
  const { sendMessage, isPublishing } = usePublish();
  const [topic, setTopic] = useState('test/topic');
  const [message, setMessage] = useState('Hello MQTT');

  const handlePublish = async () => {
    const result = await sendMessage(topic, message);
    if (result.success) {
      console.log('Message published successfully');
    }
  };

  return (
    <div>
      <h2>Publish Message</h2>
      <input 
        type="text" 
        value={topic} 
        onChange={(e) => setTopic(e.target.value)} 
        placeholder="Topic"
      />
      <input 
        type="text" 
        value={message} 
        onChange={(e) => setMessage(e.target.value)} 
        placeholder="Message"
      />
      <button onClick={handlePublish} disabled={isPublishing}>
        {isPublishing ? 'Publishing...' : 'Publish'}
      </button>
    </div>
  );
}

// Message subscriber component
function MessageSubscriber() {
  const [topic, setTopic] = useState('test/topic');
  const { messages, isSubscribed } = useMessages(topic, 10);

  return (
    <div>
      <h2>Subscribe to Messages</h2>
      <input 
        type="text" 
        value={topic} 
        onChange={(e) => setTopic(e.target.value)} 
        placeholder="Topic"
      />
      <p>Status: {isSubscribed ? 'Subscribed' : 'Not subscribed'}</p>

      <div className="messages">
        <h3>Received Messages</h3>
        {messages.length === 0 ? (
          <p>No messages received</p>
        ) : (
          <ul>
            {messages.map((msg, idx) => (
              <li key={idx}>
                <div>{msg.topic} - {new Date(msg.timestamp).toLocaleTimeString()}</div>
                <div>{typeof msg.payload === 'object' ? JSON.stringify(msg.payload) : String(msg.payload)}</div>
              </li>
            ))}
          </ul>
        )}
      </div>
    </div>
  );
}

export default App;

API Reference

Creating a Client

import { Mqtt } from 'await-mqtt';

// Create and connect with default options
const mqtt = await Mqtt({
  url: 'mqtt://broker.example.com'
});

// Create and connect with custom options
const mqtt = await Mqtt({
  url: 'mqtt://broker.example.com',
  clientId: 'my-client',
  clean: true,
  keepalive: 30,
  // Additional await-mqtt options
  autoReconnect: true,
  reconnectInterval: 1000,
  maxReconnectAttempts: 10
});

Connection Management

Since the Mqtt function connects automatically, you typically don't need to call connect separately. However, if you need to reconnect:

reconnect()

Reconnect to the broker if disconnected.

// Reconnect to the broker
await mqtt.reconnect();

end(force?)

Disconnect from the broker.

// Graceful disconnect (default)
await mqtt.end();

// Force disconnect immediately
await mqtt.end(true);

reconnect(clean?)

Manually trigger a reconnection.

await mqtt.reconnect();

// Reconnect with clean session
await mqtt.reconnect(true);

Messaging

publish(topic, payload, options?)

Publish a message to a topic with Promise support.

// String payload
await mqtt.publish('home/lights/living-room', 'ON');

// Buffer payload
await mqtt.publish('home/sensor/data', Buffer.from([0x01, 0x02, 0x03]));

// Object payload (automatically JSON serialized)
await mqtt.publish('home/settings', {
  brightness: 80,
  color: '#FFFFFF',
  mode: 'auto'
});

// With QoS and other options
await mqtt.publish('home/alerts', 'MOTION_DETECTED', {
  qos: 2,
  retain: true,
  timeout: 5000 // ms, await-mqtt specific
});

subscribe(topic, options?)

Subscribe to topics with flexible formats.

// Single topic
await mqtt.subscribe('home/temperature');

// Multiple topics as array
await mqtt.subscribe(['home/temperature', 'home/humidity']);

// With QoS
await mqtt.subscribe('home/temperature', { qos: 1 });

// Multiple topics with different QoS levels
await mqtt.subscribe({
  'home/temperature': { qos: 0 },
  'home/humidity': { qos: 1 },
  'home/pressure': { qos: 2 }
});

// With timeout
await mqtt.subscribe('home/#', { 
  qos: 1,
  timeout: 5000 // ms, await-mqtt specific
});

unsubscribe(topic, options?)

Unsubscribe from topics.

// Single topic
await mqtt.unsubscribe('home/temperature');

// Multiple topics
await mqtt.unsubscribe(['home/temperature', 'home/humidity']);

// With timeout
await mqtt.unsubscribe('home/#', { 
  timeout: 5000 // ms, await-mqtt specific
});

onMessage(topic, handler)

Register message handlers with wildcard support.

// Basic handler
mqtt.onMessage('home/temperature', (topic, message) => {
  console.log(`Temperature: ${message}`);
});

// Async handler
mqtt.onMessage('home/commands', async (topic, message) => {
  const command = message.toString();
  await executeCommand(command);
  await mqtt.publish('home/commands/response', 'SUCCESS');
});

// Wildcard handler
mqtt.onMessage('home/+/temperature', (topic, message) => {
  const room = topic.split('/')[1];
  console.log(`${room} temperature: ${message}ยฐC`);
});

// Global message handler
mqtt.onMessage('#', (topic, message) => {
  console.log(`[${topic}] ${message}`);
});

React Hooks

MqttProvider

Provides MQTT context to all child components.

import { MqttProvider } from 'await-mqtt/react';

function App() {
  return (
    <MqttProvider 
      options={{ 
        clientId: 'react-app', 
        url: 'ws://broker.example.com:8883' 
      }}
      autoConnect={true}
    >
      {/* Your app components */}
    </MqttProvider>
  );
}

useMqtt

Primary hook for accessing the MQTT client and connection state.

import { useMqtt } from 'await-mqtt/react';

function ConnectionStatus() {
  const { 
    client,           // The MqttManager instance
    isConnected,      // Boolean indicating connection status
    isConnecting,     // Boolean indicating if connection is in progress
    error,            // Error object if connection failed
    connect,          // Function to connect to a broker
    disconnect,       // Function to disconnect from the broker
    publish,          // Function to publish a message
    subscribe,        // Function to subscribe to a topic
    unsubscribe,      // Function to unsubscribe from a topic
    onMessage,        // Function to register a message handler
    getSubscriptions  // Function to get active subscriptions
  } = useMqtt();

  return (
    <div>
      <div>Status: {isConnected ? 'Connected' : (isConnecting ? 'Connecting...' : 'Disconnected')}</div>
      {error && <div>Error: {error.message}</div>}
      <button onClick={() => connect('ws://broker.example.com:8883')}>Connect</button>
      <button onClick={disconnect}>Disconnect</button>
    </div>
  );
}

useSubscription

Hook for subscribing to a specific topic.

import { useSubscription } from 'await-mqtt/react';

function TopicSubscriber({ topic }) {
  const { isSubscribed, error } = useSubscription(topic, { qos: 1 });

  return (
    <div>
      <div>Topic: {topic}</div>
      <div>Status: {isSubscribed ? 'Subscribed' : 'Not subscribed'}</div>
      {error && <div>Error: {error.message}</div>}
    </div>
  );
}

useMessages

Hook for collecting messages from a specific topic.

import { useMessages } from 'await-mqtt/react';

function MessageList({ topic }) {
  const { messages, clearMessages, isSubscribed, subscriptionError } = useMessages(topic, 10);

  return (
    <div>
      <div>Topic: {topic}</div>
      <div>Status: {isSubscribed ? 'Subscribed' : 'Not subscribed'}</div>
      <button onClick={clearMessages}>Clear Messages</button>

      <ul>
        {messages.map((msg, idx) => (
          <li key={idx}>
            <div>{new Date(msg.timestamp).toLocaleTimeString()}</div>
            <div>{typeof msg.payload === 'object' 
              ? JSON.stringify(msg.payload) 
              : String(msg.payload)}
            </div>
          </li>
        ))}
      </ul>
    </div>
  );
}

useMessage

Hook for tracking the latest message from a specific topic.

import { useMessage } from 'await-mqtt/react';

function LatestMessage({ topic }) {
  const { message, clearMessage, isSubscribed, subscriptionError } = useMessage(topic);

  return (
    <div>
      <div>Topic: {topic}</div>
      <div>Status: {isSubscribed ? 'Subscribed' : 'Not subscribed'}</div>
      <button onClick={clearMessage}>Clear Message</button>

      <div>
        {message === null ? (
          <p>No message received</p>
        ) : (
          <div>
            {typeof message === 'object' 
              ? JSON.stringify(message, null, 2) 
              : String(message)}
          </div>
        )}
      </div>
    </div>
  );
}

usePublish

Hook for publishing messages with state tracking.

import { usePublish } from 'await-mqtt/react';

function MessagePublisher() {
  const { sendMessage, isPublishing, lastError } = usePublish();
  const [topic, setTopic] = useState('test/topic');
  const [message, setMessage] = useState('Hello MQTT');

  const handlePublish = async () => {
    const result = await sendMessage(topic, message, { qos: 1 });
    if (result.success) {
      console.log('Message published successfully');
    }
  };

  return (
    <div>
      <input 
        type="text" 
        value={topic} 
        onChange={(e) => setTopic(e.target.value)} 
        placeholder="Topic"
      />
      <input 
        type="text" 
        value={message} 
        onChange={(e) => setMessage(e.target.value)} 
        placeholder="Message"
      />
      <button onClick={handlePublish} disabled={isPublishing}>
        {isPublishing ? 'Publishing...' : 'Publish'}
      </button>
      {lastError && <div>Error: {lastError.message}</div>}
    </div>
  );
}

Examples

Home Automation

import { Mqtt } from 'await-mqtt';

async function setupHomeAutomation() {
  try {
    // Create and connect client
    const mqtt = await Mqtt({
      url: 'mqtt://home-broker.local',
      clientId: 'home-controller'
    });

    // Subscribe to all device commands
    await mqtt.subscribe('home/+/command');

    // Handle lights
    mqtt.onMessage('home/lights/+/command', async (topic, message) => {
      const room = topic.split('/')[2];
      const command = message.toString();

      console.log(`Setting ${room} lights to ${command}`);
      await controlLight(room, command);

      // Confirm the action
      await mqtt.publish(`home/lights/${room}/status`, command);
    });

    // Handle temperature sensors
    mqtt.onMessage('home/sensors/+/temperature', (topic, message) => {
      const room = topic.split('/')[2];
      const temperature = parseFloat(message.toString());

      console.log(`${room} temperature: ${temperature}ยฐC`);

      // Trigger climate control if needed
      if (temperature > 25) {
        mqtt.publish(`home/climate/${room}/command`, 'COOL');
      } else if (temperature < 18) {
        mqtt.publish(`home/climate/${room}/command`, 'HEAT');
      }
    });
  } catch (error) {
    console.error('Failed to setup home automation:', error);
  }
}

React Smart Home Dashboard

import React, { useState } from 'react';
import { MqttProvider, useMqtt, useMessage, usePublish } from 'await-mqtt/react';

function SmartHomeApp() {
  return (
    <MqttProvider 
      options={{ 
        url: 'ws://home-broker.local:8883',
        clientId: 'home-dashboard' 
      }}
      autoConnect={true}
    >
      <div className="smart-home-dashboard">
        <h1>Smart Home Dashboard</h1>
        <ConnectionStatus />
        <div className="rooms-grid">
          <RoomPanel room="living-room" />
          <RoomPanel room="kitchen" />
          <RoomPanel room="bedroom" />
          <RoomPanel room="bathroom" />
        </div>
      </div>
    </MqttProvider>
  );
}

function ConnectionStatus() {
  const { isConnected, isConnecting, error, connect, disconnect } = useMqtt();

  return (
    <div className="connection-status">
      <div className={`status-indicator ${isConnected ? 'connected' : 'disconnected'}`}>
        {isConnected ? 'Connected' : (isConnecting ? 'Connecting...' : 'Disconnected')}
      </div>
      {error && <div className="error-message">Error: {error.message}</div>}
      <button onClick={() => isConnected ? disconnect() : connect('ws://home-broker.local:8883')}>
        {isConnected ? 'Disconnect' : 'Connect'}
      </button>
    </div>
  );
}

function RoomPanel({ room }) {
  return (
    <div className="room-panel">
      <h2>{room.replace('-', ' ')}</h2>
      <div className="sensors">
        <TemperatureSensor room={room} />
        <HumiditySensor room={room} />
      </div>
      <div className="controls">
        <LightControl room={room} />
        <ClimateControl room={room} />
      </div>
    </div>
  );
}

function TemperatureSensor({ room }) {
  const { message } = useMessage(`home/sensors/${room}/temperature`);

  return (
    <div className="sensor temperature-sensor">
      <h3>Temperature</h3>
      <div className="sensor-value">
        {message !== null ? `${message}ยฐC` : '--'}
      </div>
    </div>
  );
}

function HumiditySensor({ room }) {
  const { message } = useMessage(`home/sensors/${room}/humidity`);

  return (
    <div className="sensor humidity-sensor">
      <h3>Humidity</h3>
      <div className="sensor-value">
        {message !== null ? `${message}%` : '--'}
      </div>
    </div>
  );
}

function LightControl({ room }) {
  const { message: status } = useMessage(`home/lights/${room}/status`);
  const { sendMessage } = usePublish();

  const isOn = status === 'ON';

  const toggleLight = async () => {
    const newStatus = isOn ? 'OFF' : 'ON';
    await sendMessage(`home/lights/${room}/command`, newStatus);
  };

  return (
    <div className="control light-control">
      <h3>Lights</h3>
      <button 
        className={`toggle-button ${isOn ? 'on' : 'off'}`}
        onClick={toggleLight}
      >
        {isOn ? 'ON' : 'OFF'}
      </button>
    </div>
  );
}

function ClimateControl({ room }) {
  const { message: currentMode } = useMessage(`home/climate/${room}/status`);
  const { sendMessage } = usePublish();

  const setMode = async (mode) => {
    await sendMessage(`home/climate/${room}/command`, mode);
  };

  return (
    <div className="control climate-control">
      <h3>Climate</h3>
      <div className="mode-buttons">
        <button 
          className={`mode-button ${currentMode === 'OFF' ? 'active' : ''}`}
          onClick={() => setMode('OFF')}
        >
          Off
        </button>
        <button 
          className={`mode-button ${currentMode === 'HEAT' ? 'active' : ''}`}
          onClick={() => setMode('HEAT')}
        >
          Heat
        </button>
        <button 
          className={`mode-button ${currentMode === 'COOL' ? 'active' : ''}`}
          onClick={() => setMode('COOL')}
        >
          Cool
        </button>
        <button 
          className={`mode-button ${currentMode === 'AUTO' ? 'active' : ''}`}
          onClick={() => setMode('AUTO')}
        >
          Auto
        </button>
      </div>
    </div>
  );
}

export default SmartHomeApp;

License

MIT