diff --git a/browser-clients/eclipse-pahojs/mqtt-midi-client/sketch.js b/browser-clients/eclipse-pahojs/mqtt-midi-client/sketch.js
index 2121664..0336f53 100644
--- a/browser-clients/eclipse-pahojs/mqtt-midi-client/sketch.js
+++ b/browser-clients/eclipse-pahojs/mqtt-midi-client/sketch.js
@@ -9,7 +9,7 @@
but has also been tested on https://test.mosquitto.org
created 11 Nov 2020
- modiified 23 Nov 2020
+ modified 23 Nov 2020
by Tom Igoe
*/
diff --git a/browser-clients/eclipse-pahojs/mqtt-midi-controller/script.js b/browser-clients/eclipse-pahojs/mqtt-midi-controller/script.js
index cf86946..194443e 100644
--- a/browser-clients/eclipse-pahojs/mqtt-midi-controller/script.js
+++ b/browser-clients/eclipse-pahojs/mqtt-midi-controller/script.js
@@ -10,7 +10,7 @@
but has also been tested on https://test.mosquitto.org
created 11 Nov 2020
- modiified 12 Apr 2021
+ modified 12 Apr 2021
by Tom Igoe
*/
diff --git a/browser-clients/eclipse-pahojs/readme.md b/browser-clients/eclipse-pahojs/readme.md
index 0af88f0..58f8011 100644
--- a/browser-clients/eclipse-pahojs/readme.md
+++ b/browser-clients/eclipse-pahojs/readme.md
@@ -1,7 +1,6 @@
# Eclipse PAHO JavaScript Library
-* [Eclipse PAHO home](https://www.eclipse.org/paho/index.php?page=clients/js/index.php)
-* [PAHO JS documentation](https://www.eclipse.org/paho/files/jsdoc/index.html)
+There is an MQTT client library from the Eclipse foundation, the [Eclipse PAHO library](https://github.com/eclipse-paho/paho.mqtt.javascript), but it appears to be no longer supported by the foundation.
There are several examples for Eclipse PAHO in [this directory]({{site.codeurl}}/browser-clients/eclipse-pahojs/).
diff --git a/browser-clients/mqttjs/mqtt-midi-controller/index.html b/browser-clients/mqttjs/mqtt-midi-controller/index.html
new file mode 100644
index 0000000..59bc469
--- /dev/null
+++ b/browser-clients/mqttjs/mqtt-midi-controller/index.html
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+ Document
+
+
+
MIDI MQTT Message Sender and Receiver
+
This page connects to an MQTT broker, and uses WebMIDI to connect to any MIDI inputs or outputs on your system. It will auto-detect new MIDI devices as they are connected or disconnected from your system.
+
When a MIDI message is received, it is converted to an MQTT message on a topic called Midi, and sent out to the MQTT broker. Likewise, when an MQTT message is received, it is converted to a MIDI message and sent to the selected MIDI output device.
+
You can also generate MIDI messages (and MQTT messages) by typing the keys below.
+
The Local Echo checkbox selects whether the MIDI output takes messages from local sources, or just from MQTT.
+
+
+
+
+
local messages will go here
+
waiting for messages
+
messages will go here
+
+
Keyboard Input:
+ W E T Y U O
+ A S D F G H J K L
+ C3 D3 E3 F3 G3 A4 B4 C4 D4
+
+
\ No newline at end of file
diff --git a/browser-clients/mqttjs/mqtt-midi-controller/script.js b/browser-clients/mqttjs/mqtt-midi-controller/script.js
new file mode 100644
index 0000000..dfddef1
--- /dev/null
+++ b/browser-clients/mqttjs/mqtt-midi-controller/script.js
@@ -0,0 +1,391 @@
+/*
+ p5.js MQTT and MIDI Client
+ This example uses the mqtt.js library: https://www.npmjs.com/package/mqtt
+ and the Web MIDI API (https://www.w3.org/TR/webmidi/)
+ to create an MQTT client that sends and receives MQTT messages
+ that are MIDI messages.
+ You can use keyboard input as well, as shown in the HTML.
+ The client is set up for use on the shiftr.io test MQTT broker (https://public.cloud.shiftr.io),
+ but has also been tested on https://test.mosquitto.org
+
+ created 11 Nov 2020
+ modified 19 Feb 2025
+ by Tom Igoe
+*/
+
+// All these brokers work with this code.
+// Uncomment the one you want to use.
+
+////// emqx. Works in both basic WS and TLS WS:
+// const broker = 'wss://broker.emqx.io:8084/mqtt'
+// const broker = 'ws://broker.emqx.io:8083/mqtt'
+
+//////// shiftr.io desktop client.
+// Fill in your desktop IP address for localhost:
+// const broker = 'ws://localhost:1884';
+
+//////// shiftr.io, requires username and password
+// (see options variable below):
+const broker = 'wss://public.cloud.shiftr.io';
+
+//////// test.mosquitto.org, uses no username and password:
+// const broker = 'wss://test.mosquitto.org:8081';
+
+// MQTT client:
+let client;
+
+// connection options:
+let options = {
+ // Clean session
+ clean: true,
+ // connect timeout in ms:
+ connectTimeout: 10000,
+ // Authentication
+ // add a random number for a unique client ID:
+ clientId: 'jsMidiClient-' + Math.floor(Math.random() * 1000000),
+ // add these in for public.cloud.shiftr.io:
+ username: 'public',
+ password: 'public'
+}
+
+// topic to subscribe to when you connect
+// For shiftr.io, use whatever word you want for the subtopic
+// unless you have an account on the site. This will reduce
+// the traffic from others.
+let subTopic = '';
+let topic = 'midi';
+
+// HTML divs for local and remote messages
+let localDiv;
+let remoteDiv;
+
+// select menus for MIDI inputs and outputs:
+let inputSelect, outputSelect;
+
+// arrays for the MIDI devices:
+let outputDevices = new Array();
+let inputDevices = new Array();
+
+// variables for the currently selected ones:
+let currentOutput, currentInput;
+// local echo checkbox input:
+let localEcho;
+
+// an HTML div for messages:
+let messageDiv;
+
+function setup() {
+ // put the divs in variables for ease of use:
+ localDiv = document.getElementById('local');
+ remoteDiv = document.getElementById('remote');
+
+ // set text of localDiv:
+ localDiv.innerHTML = 'trying to connect';
+ // attempt to connect:
+ client = mqtt.connect(broker, options);
+ // set listeners:
+ client.on('connect', onConnect);
+ client.on('close', onDisconnect);
+ client.on('message', onMessage);
+ client.on('error', onError);
+
+ // create keyPress and keyRelease listeners:
+ document.addEventListener('keydown', keyPressed);
+ document.addEventListener('keyup', keyReleased);
+
+ // get the local echo checkbox:
+ localEcho = document.getElementById("echo");
+
+ // get the select menus:
+ inputSelect = document.getElementById("inputs");
+ inputSelect.addEventListener('change', selectInput);
+ inputSelect[0] =
+ new Option('--Choose a MIDI input:--', 0, false, false);
+
+ outputSelect = document.getElementById("outputs");
+ outputSelect.addEventListener('change', selectOutput);
+ outputSelect[0] =
+ new Option('--Choose a MIDI output:--', 0, false, false);
+ // get the message div:
+ messageDiv = document.getElementById('messages');
+
+ // initialize MIDI and get device lists:
+ navigator.requestMIDIAccess()
+ .then(getDevices);
+}
+
+function keyPressed(event) {
+ keyAction(event.keyCode, 'down');
+}
+
+function keyReleased(event) {
+ keyAction(event.keyCode, 'up');
+}
+
+// sends a noteon or noteoff MIDI message for different keys:
+function keyAction(key, direction) {
+ // keycodes for notes. See
+ // https://sonicbloom.net/en/ableton-live-tutorial-computer-keyboard-as-midi-controller/
+ // for layout:
+ let keys = [65, 87, 83, 69, 68, 70, 84, 71, 89, 72, 85, 74, 75, 79, 76, 91];
+ // first note is A3 (MIDI value 48):
+ let baseNote = 48;
+ // if they typed a key that's not one of the array,
+ // quit the function:
+ if (!keys.includes(key)) return;
+ // calculate MIDI note value:
+ let thisNote = keys.indexOf(key) + baseNote;
+ // make a MIDI command array:
+ let midiCmd = new Uint8Array(3);
+ // The note value is the second byte of the MIDI command:
+ midiCmd[1] = thisNote;
+ // up = noteOff (0x80), down = noteOn (0x90)
+ // third byte is velocity (0x70 = reasonably loud):
+ if (direction === 'up') {
+ midiCmd[0] = 0x80;
+ midiCmd[2] = 0x00;
+ } else {
+ midiCmd[0] = 0x90;
+ midiCmd[2] = 0x70;
+ }
+ // print the MIDI bytes as hexadeciimal values:
+ messageDiv.innerHTML = "MIDI message:"
+ for (var i = 0; i < midiCmd.length; i++) {
+ messageDiv.innerHTML += " 0x" + midiCmd[i].toString(16);
+ }
+ // if there is a current MIDIoutput,
+ // and localEcho is checked send it there:
+ if (currentOutput != null && localEcho.checked) {
+ currentOutput.send(midiCmd);
+ }
+ // send it by MQTT as well:
+ sendMqttMessage(midiCmd.buffer);
+}
+
+// start everything when the DOM content loads:
+window.addEventListener('DOMContentLoaded', setup);
+
+/////////////////////////////// MQTT functions
+
+// handler for mqtt connect event:
+function onConnect() {
+ // update localDiv text:
+ localDiv.innerHTML = 'connected to broker. Subscribing...'
+ // subscribe to the topic:
+ client.subscribe(topic, onSubscribe);
+}
+
+// handler for mqtt disconnect event:
+function onDisconnect() {
+ // update localDiv text:
+ localDiv.innerHTML = 'disconnected from broker.'
+}
+
+// handler for mqtt error event:
+function onError(error) {
+ // update localDiv text:
+ localDiv.innerHTML = error;
+}
+
+// handler for mqtt subscribe event:
+function onSubscribe(response, error) {
+ if (!error) {
+ // update localDiv text:
+ localDiv.innerHTML = 'Subscribed to broker.';
+ } else {
+ // update localDiv text with the error:
+ localDiv.innerHTML = error;
+ }
+}
+
+// called when an MQTT message arrives
+function onMessage(topic, payload, packet) {
+ // print what you sent in a fancy hexadecimal string:
+ let result = 'I got a message: ';
+ // convert the array to a hex string:
+ for (var i = 0; i < payload.length; i++) {
+ result += ' 0x' + payload[i].toString(16);
+ };
+ remoteDiv.innerHTML = result;
+ // set up an arrayBuffer and a Uint8 array for the incoming:
+ let incomingBuffer = new ArrayBuffer(payload.length);
+ let midiCmd = new Uint8Array(incomingBuffer);
+
+ // move the message payload into the UInt8 array:
+ for (var i = 0; i < payload.length; i++) {
+ midiCmd[i] = payload[i];
+ }
+
+ // if the message is intended for the current MIDIoutput,
+ // send it there:
+ if (currentOutput != null) {
+ currentOutput.send(midiCmd);
+ }
+}
+
+// called when you want to send a message:
+function sendMqttMessage(msg) {
+ // if the client is connected to the MQTT broker:
+ // convert the message to a byte array for printing:
+ let bytes = new Uint8Array(msg);
+
+ if (client.connected) {
+ client.publish(topic, bytes);
+ // update localDiv text
+ // print what you sent in a fancy hexadecimal string:
+ let result = 'I sent: ';
+ // function to convert a number to a hex string:
+ for (var i = 0; i < bytes.length; i++) {
+ result += ' 0x' + bytes[i].toString(16);
+ };
+ localDiv.innerHTML = result;
+ }
+
+ // if (client.isConnected()) {
+ // // start an MQTT message:
+ // message = new Paho.MQTT.Message(msg);
+ // // choose the destination topic:
+ // message.destinationName = topic;
+ // // send it:
+ // client.send(message);
+ // // convert the message to a byte array for printing:
+ // let bytes = new Uint8Array(message.payloadBytes);
+ // // print what you sent in a fancy hexadecimal string:
+ // let result = 'I sent: ';
+ // // function to convert a number to a hex string:
+ // for (var i = 0; i < bytes.length; i++) {
+ // result += ' 0x' + bytes[i].toString(16);
+ // };
+ // localDiv.innerHTML = result;
+ // }
+}
+
+// MIDI Functions /////////////////////////////////////////////////////
+
+// Get lists of available MIDI controllers
+function getDevices(midiAccess) {
+ const inputs = midiAccess.inputs.values();
+ const outputs = midiAccess.outputs.values();
+
+ // add inputs and outputs to the global arrays and the select menus:
+ for (let i of inputs) {
+ addMidiItem(i);
+ }
+ for (let o of outputs) {
+ addMidiItem(o);
+ }
+
+ // if any of the devices change state, add or delete it:
+ midiAccess.onstatechange = function (item) {
+ // if an item changes state, add it or delete it from the select menus:
+ if (item.port.state == 'connected') {
+ addMidiItem(item.port);
+ }
+ if (item.port.state == 'disconnected') {
+ removeMidiItem(item.port);
+ }
+
+ // Print information about the changed MIDI controller:
+ messageDiv.innerHTML = item.port.name + " "
+ + item.port.state;
+ };
+}
+
+// add new MIDI devices:
+function addMidiItem(midiItem) {
+ // add to the appropriate select menu,
+ // but make sure it's not already in the list:
+ if (midiItem.type == 'input' && inputDevices.indexOf(midiItem) < 0) {
+ let optionNumber = inputSelect.options.length;
+ inputSelect[optionNumber] =
+ new Option(midiItem.name, false, false);
+ // add to the devices array too:
+ inputDevices.push(midiItem);
+ }
+ if (midiItem.type == 'output' && outputDevices.indexOf(midiItem) < 0) {
+ let optionNumber = outputSelect.options.length;
+ outputSelect[optionNumber] =
+ new Option(midiItem.name, false, false);
+ // add to the devices array too:
+ outputDevices.push(midiItem);
+ }
+
+ // add a message listener:
+ midiItem.onmidimessage = getMIDIMessage;
+}
+
+// remove items when they go away:
+function removeMidiItem(midiItem) {
+ // choose the right select menu:
+ if (midiItem.type == 'input') {
+ selectMenu = inputSelect;
+ // remove the item that's disconnected:
+ inputDevices.splice(inputDevices.indexOf(midiItem), 1);
+ }
+ if (midiItem.type == 'output') {
+ selectMenu = outputSelect;
+ // remove the item that's disconnected:
+ outputDevices.splice(outputDevices.indexOf(midiItem), 1);
+ }
+
+ // clear the message listener:
+ midiItem.onmidimessage = null;
+
+ // delete the item from the menu:
+ for (let i = 0; i < selectMenu.options.length; i++) {
+ if (selectMenu.options[i].innerHTML === midiItem.name) {
+ selectMenu.options[i].remove();
+ }
+ }
+}
+
+// select the current input or output from the select menus:
+function selectInput(evt) {
+ let selected = evt.target.selectedIndex;
+ // iterate over the list of devices:
+ for (let i of inputDevices) {
+ if (i.name === inputSelect.options[selected].innerHTML) {
+ currentInput = i;
+ }
+ }
+ // if they chose the default position, clear the current input:
+ if (inputSelect.options[selected] == 0) {
+ currentInput = null;
+ }
+}
+
+function selectOutput(evt) {
+ let selected = evt.target.selectedIndex;
+ // iterate over the list of devices:
+ for (let o of outputDevices) {
+ if (o.name === outputSelect.options[selected].innerHTML) {
+ currentOutput = o;
+ }
+ }
+ // if they chose the default position, clear the current output:
+ if (outputSelect.options[selected] == 0) {
+ currentOutput = null;
+ }
+}
+
+// MIDI message listener function:
+function getMIDIMessage(message) {
+ // if the message came from a device other than the current input, you're done:
+ if (currentInput !== message.currentTarget) return;
+
+ // print the message (print the MIDI bytes as hexadeciimal values):
+ messageDiv.innerHTML = "MIDI message:"
+ for (var i = 0; i < message.data.length; i++) {
+ messageDiv.innerHTML += " 0x" + message.data[i].toString(16);
+ }
+
+ // if the message is intended for the current output, send it there:
+ if (currentOutput != null) {
+ currentOutput.send(message.data);
+ }
+
+ // if connected to MQTT, send message as MQTT message:
+ if (client.isConnected()) {
+ sendMqttMessage(message.data.buffer);
+ }
+}
\ No newline at end of file
diff --git a/browser-clients/mqttjs/mqtt-midi-controller/style.css b/browser-clients/mqttjs/mqtt-midi-controller/style.css
new file mode 100644
index 0000000..fb56715
--- /dev/null
+++ b/browser-clients/mqttjs/mqtt-midi-controller/style.css
@@ -0,0 +1,17 @@
+body {
+ font-family: Arial, Helvetica, sans-serif;
+}
+#black-keys {
+ font-size: 24px;
+ letter-spacing: 5px;
+}
+
+#white-keys {
+ font-size: 24px;
+ letter-spacing: 5px;
+}
+
+#notes {
+ font-size: 12px;
+ word-spacing: 14px;
+}
\ No newline at end of file
diff --git a/browser-clients/mqttjs/MqttJsClientSimple/index.html b/browser-clients/mqttjs/mqttjs-client-simple/index.html
similarity index 66%
rename from browser-clients/mqttjs/MqttJsClientSimple/index.html
rename to browser-clients/mqttjs/mqttjs-client-simple/index.html
index 486c779..342e560 100644
--- a/browser-clients/mqttjs/MqttJsClientSimple/index.html
+++ b/browser-clients/mqttjs/mqttjs-client-simple/index.html
@@ -1,10 +1,7 @@
-
-
+
diff --git a/browser-clients/mqttjs/MqttJsClientSimple/script.js b/browser-clients/mqttjs/mqttjs-client-simple/script.js
similarity index 100%
rename from browser-clients/mqttjs/MqttJsClientSimple/script.js
rename to browser-clients/mqttjs/mqttjs-client-simple/script.js
diff --git a/browser-clients/mqttjs/mqttjs-p5js-mousepressed-client/index.html b/browser-clients/mqttjs/mqttjs-p5js-mousepressed-client/index.html
new file mode 100644
index 0000000..3f0ecbb
--- /dev/null
+++ b/browser-clients/mqttjs/mqttjs-p5js-mousepressed-client/index.html
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/browser-clients/mqttjs/mqttjs-p5js-mousepressed-client/sketch.js b/browser-clients/mqttjs/mqttjs-p5js-mousepressed-client/sketch.js
new file mode 100644
index 0000000..e35a3e3
--- /dev/null
+++ b/browser-clients/mqttjs/mqttjs-p5js-mousepressed-client/sketch.js
@@ -0,0 +1,137 @@
+/*
+ p5.js MQTT Client example
+ This example uses p5.js: https://p5js.org/
+ and the mqtt.js client library: https://www.npmjs.com/package/mqtt
+ to create an MQTT client that sends and receives MQTT messages.
+ The client is set up for use on the shiftr.io test MQTT broker,
+ but other options listed will work.
+
+ created 12 June 2020
+ modified 19 Feb 2025
+ by Tom Igoe
+*/
+
+// All these brokers work with this code.
+// Uncomment the one you want to use.
+
+////// emqx. Works in both basic WS and TLS WS:
+// const broker = 'wss://broker.emqx.io:8084/mqtt'
+// const broker = 'ws://broker.emqx.io:8083/mqtt'
+
+//////// shiftr.io desktop client.
+// Fill in your desktop IP address for localhost:
+// const broker = 'ws://localhost:1884';
+
+//////// shiftr.io, requires username and password
+// (see options variable below):
+const broker = 'wss://public.cloud.shiftr.io';
+
+//////// test.mosquitto.org, uses no username and password:
+// const broker = 'wss://test.mosquitto.org:8081';
+
+// MQTT client:
+let client;
+// connection options:
+let options = {
+ // Clean session
+ clean: true,
+ // connect timeout in ms:
+ connectTimeout: 10000,
+ // Authentication
+ // add a random number for a unique client ID:
+ clientId: 'mqttJsClient-' + Math.floor(Math.random()*1000000) ,
+ // add these in for public.cloud.shiftr.io:
+ username: 'public',
+ password: 'public'
+ }
+
+
+// topic to subscribe to when you connect:
+let topic = 'monkey';
+// divs to show messages:
+let localDiv, remoteDiv;
+
+// position of the circle
+let xPos, yPos;
+
+function setup() {
+ createCanvas(400, 400);
+ // Create an MQTT client:
+ // attempt to connect:
+ client = mqtt.connect(broker, options);
+ // set listeners:
+ client.on('connect', onConnect);
+ client.on('close', onDisconnect);
+ client.on('message', onMessage);
+ client.on('error', onError);
+
+ // create a div for local messages:
+ localDiv = createDiv('local messages will go here');
+ localDiv.position(20, 50);
+ // create a div for the response:
+ remoteDiv = createDiv('waiting for messages');
+ remoteDiv.position(20, 80);
+}
+
+function draw() {
+ background(255);
+ noStroke();
+ // draw a circle when a message is received:
+ fill('#2398CE');
+ // circle moves with the message:
+ circle(xPos, yPos, 30);
+}
+
+function mousePressed() {
+ sendMqttMessage(mouseX + ',' + mouseY);
+}
+
+// called when the client connects
+function onConnect() {
+ localDiv.html('client is connected');
+ client.subscribe(topic);
+}
+ // handler for mqtt disconnect event:
+ function onDisconnect() {
+ // update localDiv text:
+ localDiv.html('disconnected from broker.');
+ }
+
+ // handler for mqtt error event:
+ function onError(error) {
+ // update localDiv text:
+ localDiv.html(error);
+ }
+
+ // handler for mqtt subscribe event:
+ function onSubscribe(response, error) {
+ if (!error) {
+ // update localDiv text:
+ localDiv.html('Subscribed to broker.');
+ } else {
+ // update localDiv text with the error:
+ localDiv.html(error);
+ }
+ }
+
+// called when a message arrives
+function onMessage(topic, payload, packet) {
+ let message = payload.toString();
+ remoteDiv.html('I got a message:' + message);
+ // assume the message is two numbers, mouseX and mouseY.
+ // Split it into an array:
+ let values = message.split(',');
+ // convert the array values into numbers:
+ xPos = Number(values[0]);
+ yPos = Number(values[1]);
+}
+
+// called when you want to send a message:
+function sendMqttMessage(msg) {
+ // if the client is connected to the MQTT broker:
+ if (client.connected) {
+ client.publish(topic, msg);
+ // update localDiv text
+ localDiv.html('I sent: ' + msg);
+ }
+}
\ No newline at end of file
diff --git a/browser-clients/mqttjs/mqttjsHueLightControl/index.html b/browser-clients/mqttjs/mqttjsHueLightControl/index.html
new file mode 100644
index 0000000..5e54fe2
--- /dev/null
+++ b/browser-clients/mqttjs/mqttjsHueLightControl/index.html
@@ -0,0 +1,12 @@
+
+
+
+
+ public
+
+
+
+
+
+
+
diff --git a/browser-clients/mqttjs/mqttjsHueLightControl/sketch.js b/browser-clients/mqttjs/mqttjsHueLightControl/sketch.js
new file mode 100644
index 0000000..1a9f9d0
--- /dev/null
+++ b/browser-clients/mqttjs/mqttjsHueLightControl/sketch.js
@@ -0,0 +1,205 @@
+/*
+ Hue Hub light control over MQTT
+
+ This example will change the brightness of a light
+ on a local hub when you change the slider, and will
+ send an MQTT message with the value of the slider
+ when you press the button. If it receives an MQTT message
+ on the `lights` topic, it uses that value to change the
+ brightness of the light. So you can use this
+ to change the brightness of a local hub, or of a
+ friend's hub on a remote network if you are both connected
+ to the same broker.
+
+ created 23 July 2020
+ modified 18 Feb 2025
+ by Tom Igoe
+*/
+// Fill in your hue hub IP credentials here:
+let url = '192.168.0.8';
+let username = 'xxxxxxxx-xxxxxxxxx';
+// slider for dimming the lights:
+let dimmer;
+// the number of the light in the hub:
+let lightNumber = 3;
+// The light state:
+let lightState = {
+ bri: 0,
+ on: false
+}
+
+// All these brokers work with this code.
+// Uncomment the one you want to use.
+
+////// emqx. Works in both basic WS and TLS WS:
+// const broker = 'wss://broker.emqx.io:8084/mqtt'
+// const broker = 'ws://broker.emqx.io:8083/mqtt'
+
+//////// shiftr.io desktop client.
+// Fill in your desktop IP address for localhost:
+// const broker = 'ws://localhost:1884';
+
+//////// shiftr.io, requires username and password
+// (see options variable below):
+const broker = 'wss://public.cloud.shiftr.io';
+
+//////// test.mosquitto.org, uses no username and password:
+// const broker = 'wss://test.mosquitto.org:8081';
+
+// MQTT client:
+let client;
+// client credentials:
+let clientID = 'p5HueClient';
+
+let options = {
+ // Clean session
+ clean: true,
+ // connect timeout in ms:
+ connectTimeout: 10000,
+ // Authentication
+ // add a random number for a unique client ID:
+ clientId: 'mqttJsClient-' + Math.floor(Math.random()*1000000) ,
+ // add these in for public.cloud.shiftr.io:
+ username: 'public',
+ password: 'public'
+ }
+
+// topic to subscribe to when you connect to the broker:
+let topic = 'lights';
+
+// UI elements:
+// a pushbutton to send messages:
+let sendButton;
+// divs for text from the broker:
+let localDiv;
+let remoteDiv;
+
+function setup() {
+ noLoop();
+ // createCanvas(windowWidth, windowHeight);
+ // a div for the Hue hub's responses:
+ remoteDiv = createDiv('Hub response');
+ // position it:
+ remoteDiv.position(20, 130);
+ // a slider to dim one light:
+ dimmer = createSlider(0, 254, 127)
+ // position it:
+ dimmer.position(10, 10);
+ // set a behavior for it:
+ dimmer.mouseReleased(changeBrightness);
+
+ // attempt to connect:
+ client = mqtt.connect(broker, options);
+ // set listeners:
+ client.on('connect', onConnect);
+ client.on('close', onDisconnect);
+ client.on('message', onMessage);
+ client.on('error', onError);
+
+ // create the send button:
+ sendButton = createButton('send a message');
+ sendButton.position(20, 40);
+ sendButton.mousePressed(sendMqttMessage);
+ // create a div for local messages:
+ localDiv = createDiv('local messages will go here');
+ localDiv.position(20, 70);
+ // create a div for the response:
+ remoteDiv = createDiv('waiting for messages');
+ remoteDiv.position(20, 100);
+ hueConnect();
+}
+
+/*
+this function makes the HTTP GET call to get the light data:
+HTTP GET http://your.hue.hub.address/api/username/lights/
+*/
+function hueConnect() {
+ url = "http://" + url + '/api/' + username + '/lights/';
+ httpDo(url, 'GET', getLights);
+}
+
+/*
+this function uses the response from the hub
+to create a new div for the UI elements
+*/
+function getLights(result) {
+ remoteDiv.html(result);
+}
+
+function changeBrightness() {
+ lightState.bri = dimmer.value();
+ if (lightState.bri > 0) {
+ lightState.on = true;
+ } else {
+ lightState.on = false;
+ }
+ // make the HTTP call with the JSON object:
+ setLight(lightNumber, lightState);
+}
+
+/*
+this function makes an HTTP PUT call to change the properties of the lights:
+HTTP PUT http://your.hue.hub.address/api/username/lights/lightNumber/state/
+and the body has the light state:
+{
+ on: true/false,
+ bri: brightness
+}
+*/
+function setLight(whichLight, data) {
+ var path = url + whichLight + '/state/';
+
+ var content = JSON.stringify(data); // convert JSON obj to string
+ httpDo(path, 'PUT', content, 'text', getLights); //HTTP PUT the change
+}
+
+// called when the client connects
+function onConnect() {
+ localDiv.html('client is connected');
+ client.subscribe(topic);
+}
+
+// called when the client loses its connection
+function onDisconnect(response) {
+ if (response.errorCode !== 0) {
+ localDiv.html('onDisconnect:' + response.errorMessage);
+ }
+}
+
+// handler for mqtt error event:
+function onError(error) {
+ // update localDiv text:
+ localDiv.html("error: " + error);
+ }
+
+// called when a message arrives
+function onMessage(topic, payload, packet) {
+ remoteDiv.html('I got a message:' + payload);
+ let incomingNumber = parseInt(payload);
+ // use it to set the light:
+ lightState.bri = incomingNumber;
+ if (lightState.bri > 0) {
+ lightState.on = true;
+ } else {
+ lightState.on = false;
+ }
+ // make the HTTP call with the JSON object:
+ setLight(lightNumber, lightState);
+}
+
+// called when you want to send a message:
+function sendMqttMessage() {
+ // if the client is connected to the MQTT broker:
+ if (client.isConnected()) {
+ // make a string with a random number form 0 to 15:
+ let msg = String(dimmer.value());
+ // start an MQTT message:
+ message = new Paho.MQTT.Message(msg);
+ // choose the destination topic:
+ message.destinationName = topic;
+ // send it:
+ client.send(message);
+ // print what you sent:
+ localDiv.html('I sent: ' + message.payloadString);
+ }
+}
\ No newline at end of file
diff --git a/browser-clients/mqttjs/readme.md b/browser-clients/mqttjs/readme.md
index 4dbe23a..d43f71d 100644
--- a/browser-clients/mqttjs/readme.md
+++ b/browser-clients/mqttjs/readme.md
@@ -2,10 +2,31 @@
These examples are based on the [mqtt.js](https://github.com/mqttjs/MQTT.js) client library.
-## MqttJsClientSimple
-* [See the example running](MqttJsClientSimple)
-* [See the source code]({{site.codeurl}}/browser-clients/mqttjs/MqttJsClientSimple)
+## mqttjs-client-simple
+* [See the example running](mqttjs-client-simple)
+* [See the source code]({{site.codeurl}}/browser-clients/mqttjs/mqttjs-client-simple)
This is a bare minimum client example for mqtt.js. On document load, the script for this page gets two divs from the HTML document for local and remote messages.Then it attempts to connect to the broker. Once it does, it sends the local time if it's connected every two seconds. The publish button allows you to turn on and off publishing status, in case you're testing with a second client that's sending to the same topic.
-The [ArduinoMqttClient example]({{site.codeurl}}/arduino-clients/ArduinoMqttClient) uses the same topic and sends the same range of numeric values if you want to test against another client.
\ No newline at end of file
+The [ArduinoMqttClient example]({{site.codeurl}}/arduino-clients/ArduinoMqttClient) uses the same topic and sends the same range of numeric values if you want to test against another client.
+
+## mqttjs-p5js-mousepressed-client
+* [See the example running](mqttjs-p5js-mousepressed-client)
+* [See the source code]({{site.codeurl}}/browser-clients/mqttjs/mqttjs-p5js-mousepressed-client)
+
+This example uses [p5.js](https://p5js.org/) and the [mqtt.js client library](https://www.npmjs.com/package/mqtt) to create an MQTT client that sends and receives MQTT messages. The client is set up for use on the [shiftr.io](https://www.shiftr.io/try/) test MQTT broker, but other options listed will work.
+
+## mqtt-midi-controller
+* [See the example running](mqtt-midi-controller)
+* [See the source code]({{site.codeurl}}/browser-clients/mqttjs/mqtt-midi-controller)
+
+This example uses the [mqtt.js library](https://www.npmjs.com/package/mqtt) and the [Web MIDI API](https://www.w3.org/TR/webmidi/) to create an MQTT client that sends and receives MQTT messages that are MIDI messages. You can use keyboard input as well, as shown in the HTML.
+The client is set up for use on the [shiftr.io test MQTT broker](https://www.shiftr.io/try/), but has also been tested on other brokers.
+
+This [Arduino MQTT-to-MIDI Player Client]({{site.codeurl}}/arduino-clients/MqttClientMIDIPlayer/MqttClientMIDIPlayer.ino) can receive MIDI messages from the same broker and send MIDI to your operating system or MIDI system. This [Arduino MIDI-to-MQTT Congtroller Client]({{site.codeurl}}/arduino-clients/MqttClientMIDIController/MqttClientMIDIController.ino) can send noteon and noteoff messages via MQTT at the push of a button.
+
+## mqttjsHueLightControl
+* [See the example running](mqttjsHueLightControl)
+* [See the source code]({{site.codeurl}}/browser-clients/mqttjs/mqttjsHueLightControl)
+
+This example will change the brightness of a light on a local [Philips Hue Hub](https://tigoe.github.io/hue-control/) when you change the slider, and will send an MQTT message with the value of the slider when you press the button. If it receives an MQTT message on the `lights` topic, it uses that value to change the brightness of the light. So you can use this to change the brightness of a local hub, or of a friend's hub on a remote network if you are both connected to the same broker.
\ No newline at end of file
diff --git a/readme.md b/readme.md
index b6a2626..19b46ca 100644
--- a/readme.md
+++ b/readme.md
@@ -25,7 +25,7 @@ There are many other Arduino MQTT libraries. Joël Gähwiler's [arduino-mqtt](ht
## JavaScript Clients
-For JavaScript clients, there are multiple libraries. The examples here use the [Eclipse PAHO library](https://www.eclipse.org/paho/index.php?page=clients/js/index.php) and the [mqtt.js library](https://github.com/mqttjs/MQTT.js#readme). They both have similar functionality, but the mqtt.js library has a bit simpler syntax, and it can be used both in the browser and in node.js scripts.
+For JavaScript clients, the most common library is the [mqtt.js library](https://github.com/mqttjs/MQTT.js#readme), which is written for both browsers and for node.js. There is a second library from the Eclipse foundation, the [Eclipse PAHO library](https://github.com/eclipse-paho/paho.mqtt.javascript), but it appears to be no longer supported by the foundation. They both have similar functionality, but the mqtt.js library has a bit simpler syntax, and it can be used both in the browser and in node.js scripts.
**NOTE:** Both of these clients use webSockets to connect to an MQTT broker initially, because they come from the browser, and browsers, can't use MQTT as of this writing (Feb. 2025). So if you are using a local broker like mosquitto, make sure it's set up to receive connections via webSockets as well as via MQTT.