notes:mqtt
Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
notes:mqtt [2024/04/18 19:44] – discord | notes:mqtt [2024/04/20 20:46] (current) – discord | ||
---|---|---|---|
Line 1: | Line 1: | ||
- | Written by Jacob Haip on April 17, 2024 | + | ====== MQTT and Microcontroller Folk Integrations ====== |
+ | Jacob Haip, April 2024 | ||
- | I am interested in integrating more physical hardware and sensors into Folk Computer to help expand | + | I am interested in integrating more physical hardware and sensors into Folk Computer to expand |
WiFi-connected microcontrollers are the primary tool I have been using to integrate sensors and actuators with Folk. Boards I have used include the [[https:// | WiFi-connected microcontrollers are the primary tool I have been using to integrate sensors and actuators with Folk. Boards I have used include the [[https:// | ||
Line 72: | Line 73: | ||
</ | </ | ||
- | === Getting a button input into Folk === | + | ===== Getting a button input into Folk ===== |
- | TODO: GIF of button press. | + | {{micro-button-press.gif}} |
<code c rpi-pico-w-micropython-button-press.py> | <code c rpi-pico-w-micropython-button-press.py> | ||
Line 174: | Line 175: | ||
</ | </ | ||
- | === Example code using the Adafruit MagTag E-Ink Microcontroller === | + | ===== Output from Folk to Microcontroller |
- | [[https:// | + | I have this cool [[https:// |
- | <code python magtag-micropython.py> | + | |
- | import os | + | |
- | import time | + | |
- | import ssl | + | |
- | import socketpool | + | |
- | import wifi | + | |
- | import adafruit_minimqtt.adafruit_minimqtt as MQTT | + | |
- | from adafruit_magtag.magtag import MagTag | + | |
- | magtag = MagTag() | + | <code c matrix-portal.c> |
- | magtag.add_text( | + | #include <SPI.h> |
- | | + | #include < |
- | 50, | + | #include < |
- | (magtag.graphics.display.height // 2) - 1, | + | #include < |
- | ), | + | |
- | text_scale=3, | + | |
- | ) | + | |
- | magtag.set_text(" | + | |
- | print(f"Connecting to {os.getenv(' | + | char ssid[] = "XXXX"; // your network SSID (name) |
- | print(f"Connecting to {os.getenv(' | + | char pass[] = "XXXX"; // your network password |
- | wifi.radio.connect(os.getenv(" | + | |
- | print(f" | + | |
- | sending_feed | + | const char* mqttServer |
- | message_feed | + | const int mqttPort = 1883; |
+ | const char* mqttTopic | ||
- | def connected(client, | + | WiFiClient espClient; |
- | client.subscribe(message_feed) | + | PubSubClient |
- | def disconnected(client, userdata, rc): | + | uint8_t rgbPins[] = {7, 8, 9, 10, 11, 12}; |
- | | + | uint8_t addrPins[] = {17, 18, 19, 20}; |
+ | uint8_t clockPin = 14; | ||
+ | uint8_t latchPin = 15; | ||
+ | uint8_t oePin = 16; | ||
- | def message(client, topic, message): | + | Adafruit_Protomatter matrix( |
- | | + | |
- | magtag.set_text(message) | + | |
- | pool = socketpool.SocketPool(wifi.radio) | + | uint64_t pixelPalette[] |
- | ssl_context = ssl.create_default_context() | + | matrix.color565(0, 0, 0), |
- | mqtt_client = MQTT.MQTT( | + | matrix.color565(157, |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | ) | + | |
+ | | ||
+ | | ||
+ | matrix.color565(47, | ||
+ | matrix.color565(68, | ||
+ | matrix.color565(163, | ||
+ | matrix.color565(27, | ||
+ | matrix.color565(0, | ||
+ | matrix.color565(49, | ||
+ | matrix.color565(178, | ||
+ | matrix.color565(255, | ||
- | # Setup the callback methods above | ||
- | mqtt_client.on_connect = connected | ||
- | mqtt_client.on_disconnect = disconnected | ||
- | mqtt_client.on_message = message | ||
- | # Connect the client to the MQTT broker. | + | //--------- WIFI ------------------------------------------- |
- | print(" | + | |
- | mqtt_client.connect() | + | |
- | test_val = 0 | + | void wifi_connect() { |
- | while True: | + | |
- | | + | delay(10); |
- | | + | WiFi.begin(ssid, |
+ | | ||
+ | | ||
+ | | ||
+ | } | ||
+ | Serial.println(" | ||
+ | Serial.println(" | ||
+ | Serial.println(WiFi.localIP()); | ||
+ | } | ||
- | # Send a new message | + | // |
- | print(f"Sending value: {test_val}...") | + | void mqtt_setup() { |
- | | + | client.setServer(mqttServer, |
- | print(" | + | client.setBufferSize(64*32 + 64); |
- | | + | client.setCallback(callback); |
+ | Serial.println(" | ||
+ | while (!client.connected()) { | ||
+ | String clientId = " | ||
+ | clientId += String(random(0xffff), | ||
+ | if (client.connect(clientId.c_str())) { | ||
+ | Serial.println(" | ||
+ | } else { | ||
+ | Serial.print(" | ||
+ | Serial.println(client.state()); | ||
+ | delay(2000); | ||
+ | } | ||
+ | } | ||
+ | |||
+ | client.subscribe(mqttTopic); | ||
+ | } | ||
+ | |||
+ | void callback(char* topic, byte* payload, unsigned int length) { | ||
+ | |||
+ | | ||
+ | Serial.println(topic); | ||
+ | |||
+ | String byteRead = ""; | ||
+ | Serial.print(" | ||
+ | for (int i = 0; i < length; i++) { | ||
+ | byteRead += (char)payload[i]; | ||
+ | | ||
+ | Serial.println(byteRead); | ||
+ | |||
+ | matrix.fillScreen(matrix.color565(0, 0, 0)); | ||
+ | |||
+ | | ||
+ | { | ||
+ | uint64_t pixelColor = matrix.color565(0, | ||
+ | String pixelChar = String(byteRead[i]); | ||
+ | int colorIndex = (int)strtol(& | ||
+ | if (colorIndex >= 0 && colorIndex < 16) | ||
+ | { | ||
+ | pixelColor = pixelPalette[colorIndex]; | ||
+ | } | ||
+ | matrix.drawPixel(i % 64, i / 64, pixelColor); | ||
+ | | ||
+ | matrix.show(); | ||
+ | } | ||
+ | |||
+ | |||
+ | void setup() | ||
+ | { | ||
+ | Serial.begin(9600); | ||
+ | |||
+ | // Initialize matrix... | ||
+ | ProtomatterStatus pmstatus = matrix.begin(); | ||
+ | Serial.print(" | ||
+ | | ||
+ | if (pmstatus != PROTOMATTER_OK) | ||
+ | { | ||
+ | for (;;) | ||
+ | ; | ||
+ | } | ||
+ | |||
+ | matrix.println(" | ||
+ | matrix.show(); | ||
+ | |||
+ | wifi_connect(); | ||
+ | |||
+ | matrix.println(" | ||
+ | matrix.show(); | ||
+ | |||
+ | mqtt_setup(); | ||
+ | } | ||
+ | |||
+ | void loop() | ||
+ | { | ||
+ | client.loop(); | ||
+ | } | ||
</ | </ | ||
- | A folk program to make a crude clock on the MagTag display: | + | And with this you can make a crude clock that fills up the screen horizontally as time passes. |
- | <code tcl crude-clock.folk> | + | |
+ | {{crude-clock.gif}} | ||
+ | |||
+ | <code tcl crude-matrixportal-clock.folk> | ||
When /node/ has step count /c/ { | When /node/ has step count /c/ { | ||
- | if {[expr {int($c) % 5000}] == 0} { | + | if {[expr {int($c) % 1000}] == 0} { |
- | set ts [clock milliseconds] | + | set currentTimeMillis [clock milliseconds] |
- | Wish MQTT publish $ts on topic jhaip/feeds/onoff at timestamp $ts | + | set millisSinceMinuteStart [expr {$currentTimeMillis % 60000}] |
+ | set fillValue [expr {$millisSinceMinuteStart * 64 / 60000}] | ||
+ | |||
+ | set matrixportaloutput "" | ||
+ | for {set y 0} {$y < 32} {incr y} { | ||
+ | for {set x 0} {$x < 64} {incr x} { | ||
+ | if {$x < $fillValue} { | ||
+ | set matrixportaloutput " | ||
+ | } else { | ||
+ | set matrixportaloutput " | ||
+ | } | ||
+ | } | ||
+ | } | ||
+ | set c [clock milliseconds] | ||
+ | Wish MQTT publish | ||
} | } | ||
} | } | ||
</ | </ | ||
- | A folk program | + | Additionally, |
- | < | + | {{matrixportal-live-edit.gif}} |
- | When MQTT claims message /message/ topic "/feeds/test" timestamp /t/ { | + | |
- | Wish $this is labelled "MagTag value: $message" | + | ===== Using MQTT on web pages for bidirectional communication with Folk ===== |
+ | |||
+ | Making simple web pages using the [[https:// | ||
+ | |||
+ | First we make a web app that plays a sound when it receives an MQTT messages: | ||
+ | |||
+ | < | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | < | ||
+ | <audio id=" | ||
+ | <source src=" | ||
+ | <source src=" | ||
+ | Your browser does not support the audio element. | ||
+ | </ | ||
+ | <script src=" | ||
+ | < | ||
+ | const clientId = ' | ||
+ | const host = ' | ||
+ | const options = { | ||
+ | keepalive: 60, | ||
+ | clientId: clientId, | ||
+ | protocolId: ' | ||
+ | protocolVersion: | ||
+ | clean: true, | ||
+ | reconnectPeriod: | ||
+ | connectTimeout: | ||
+ | will: { | ||
+ | topic: ' | ||
+ | payload: ' | ||
+ | qos: 0, | ||
+ | retain: false | ||
+ | }, | ||
+ | } | ||
+ | console.log(' | ||
+ | const client = mqtt.connect(host, | ||
+ | |||
+ | client.on(' | ||
+ | console.log(' | ||
+ | client.end() | ||
+ | }) | ||
+ | |||
+ | client.on(' | ||
+ | console.log(' | ||
+ | }) | ||
+ | |||
+ | client.on(' | ||
+ | console.log(' | ||
+ | client.subscribe('/ | ||
+ | }); | ||
+ | |||
+ | client.on(' | ||
+ | console.log(' | ||
+ | document.getElementById(" | ||
+ | document.getElementById(" | ||
+ | }); | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | </ | ||
+ | |||
+ | And then in folk you can make every phone and laptop with that web page open play a sound when a button is pressed: | ||
+ | |||
+ | {{button-horse.mp4}} | ||
+ | |||
+ | <code tcl trigger-sound.folk> | ||
+ | When MQTT claims message /message/ topic "/button1" timestamp /t/ { | ||
+ | Wish $this is labelled "BUTTON 1 PRESSED" | ||
+ | set ts [clock milliseconds] | ||
+ | Wish MQTT publish "make some noise" on topic "/ | ||
} | } | ||
</ | </ |
notes/mqtt.1713469454.txt.gz · Last modified: 2024/04/18 19:44 by discord