<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[GUI-O Application Tutorial Series]]></title><description><![CDATA[GUI-O application through practical examples]]></description><link>https://forum.gui-o.com/category/12</link><generator>RSS for Node</generator><lastBuildDate>Mon, 12 Oct 2026 00:21:48 GMT</lastBuildDate><atom:link href="https://forum.gui-o.com/category/12.rss" rel="self" type="application/rss+xml"/><pubDate>Tue, 16 Jan 2024 15:43:07 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Episode 21: GUI-O push notification from any device]]></title><description><![CDATA[<p dir="auto">This example shows how to create custom push notification on any Internet enabled device (WiFi, Ethernet) and send it to a targeted Android device.</p>
<p dir="auto"><strong>NOTE</strong>: Push notifications are available in GUI-O <strong>PRO</strong> version only.</p>
<p dir="auto"><strong>The code from this example can be combined with other GUI-O examples using MQTT, Classic Bluetooth or Low Energy Bluetooth</strong>. See <a href="https://www.gui-o.com/examples/gui-o-and-boards" rel="nofollow ugc">https://www.gui-o.com/examples/gui-o-and-boards</a>.</p>
<p dir="auto"><strong>Software prerequisites:</strong></p>
<ul>
<li>
<p dir="auto">Arduino IDE (<a href="https://www.arduino.cc/en/software" rel="nofollow ugc">https://www.arduino.cc/en/software</a>)</p>
</li>
<li>
<p dir="auto">Arduino source code (you can copy the source code from the snippet below, or download it <a href="https://drive.google.com/uc?export=download&amp;id=1tjrAR50XXDZ9dEz2BJah4jy11zTFT4Be" rel="nofollow ugc">here</a></p>
</li>
</ul>
<pre><code>/*
 * GUI-O Basic Push notification example
 *
 * Copyright (C) 2024, GUI-O Team
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */


#include &lt;WiFiClientSecure.h&gt;
#include &lt;HTTPClient.h&gt;
#include &lt;ArduinoJson.h&gt;

static const char* ssid = "&lt;ssid&gt;"; // router name
static const char* pass = "&lt;pass&gt;"; // router password
static const char* appUuid = "&lt;appUuid&gt;"; // application uuid (retrieve from GUI-O app)
static const char* resource = "https://apis.gui-o.com:9501/gui-o/resources/api/sendPushNotification"; // request resource / endpoint

static const char* letsencrypt_ca = \
"-----BEGIN CERTIFICATE-----\n" \
"MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw\n" \
"TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh\n" \
"cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4\n" \
"WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu\n" \
"ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY\n" \
"MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc\n" \
"h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+\n" \
"0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U\n" \
"A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW\n" \
"T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH\n" \
"B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC\n" \
"B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv\n" \
"KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn\n" \
"OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn\n" \
"jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw\n" \
"qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI\n" \
"rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV\n" \
"HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq\n" \
"hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL\n" \
"ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ\n" \
"3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK\n" \
"NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5\n" \
"ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur\n" \
"TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC\n" \
"jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc\n" \
"oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq\n" \
"4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA\n" \
"mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d\n" \
"emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=\n" \
"-----END CERTIFICATE-----\n";

// Connection and requests handling
WiFiClientSecure client;
HTTPClient http;

// Icoming data buffer
String in;

void setup() {
  // Debug output
  Serial.begin(115200);
  
  // Connect WiFi (keep trying...)
  Serial.print("Connecting to ");
  Serial.println(ssid);
  
  // Start WiFi
  WiFi.begin(ssid, pass);
  while(WiFi.status() != WL_CONNECTED) { 
    Serial.print(".");
    delay(500); 
  }

  // Set root CA
  client.setCACert(letsencrypt_ca);
  
  Serial.println("WiFi connected!");
}

void loop() {
  while(Serial.available()) {
    const char c = Serial.read();
    in += c;
  
    if(c == '\n') {
      // Send push notification
      sendPushNotification("GUI-O push notification example", in.c_str(), appUuid);
      // clear buffer
      in = "";
    }  
  }  
}

void sendPushNotification(const char* title, const char* message, const char* appUuid) {
  DynamicJsonDocument jsonPayload(512);
  jsonPayload["appUuid"] = String(appUuid);
  jsonPayload["messageTitle"] = String(title);
  jsonPayload["messageText"] = String(message);

  String payload;
  serializeJson(jsonPayload, payload);

  if (http.begin(client, resource)) {
      http.addHeader("Content-Type", "application/json");

      const int httpCode = http.POST(payload);

      if (httpCode == HTTP_CODE_OK) {
        String response = http.getString();
        Serial.print("Response: ");
        Serial.println(response);
      } 
      else {
        Serial.print("Request failed. Status code: ");
        Serial.println(httpCode);
      }

      http.end();
  }
}
</code></pre>
<ul>
<li>GUI-O application (<a href="https://play.google.com/store/apps/details?id=com.guio.guioapp" rel="nofollow ugc">https://play.google.com/store/apps/details?id=com.guio.guioapp</a>)</li>
</ul>
<p dir="auto"><strong>Hardware prerequisites:</strong></p>
<ul>
<li>Any Internet enabled board (WiFi, Ethernet) that is compatible with Arduino IDE</li>
</ul>
<h3>1. Retrieve application's universally unique identifier (UUID)</h3>
<ul>
<li>
<p dir="auto">Open GUI-O application, navigate to settings and select "Info"</p>
</li>
<li>
<p dir="auto">Verify that the text "Available" is displayed under "Push notifications" entry</p>
</li>
<li>
<p dir="auto">Make a note of "Application UUID" (you can share the "Application UUID" by tapping on it)</p>
</li>
</ul>
<h3>2. Modify and upload the code</h3>
<ul>
<li>
<p dir="auto">Open Arduino IDE</p>
</li>
<li>
<p dir="auto">Select "File -&gt; Open"</p>
</li>
<li>
<p dir="auto">Navigate to location where BasicPushNotification.zip archive was extracted (if downloaded)</p>
</li>
<li>
<p dir="auto">Select BasicPushNotification.ino and confirm</p>
</li>
<li>
<p dir="auto">Set your router name and password</p>
</li>
<li>
<p dir="auto">Set your "Application UUID" (retrieved in form the GUI-O app)</p>
</li>
<li>
<p dir="auto">Make sure that your board is connected to your PC</p>
</li>
<li>
<p dir="auto">Ensure that the correct port and baud rate are selected</p>
</li>
<li>
<p dir="auto">Press upload button to start code upload</p>
</li>
</ul>
<h3>3. Send a push notification</h3>
<ul>
<li>
<p dir="auto">Open any serial terminal and connect to your board (baud rate 115200)</p>
</li>
<li>
<p dir="auto">Enter your push notification message on the serial terminal - the text must be terminated with the <strong>\n</strong> (new line) character.</p>
</li>
<li>
<p dir="auto">Observe the response on the serial terminal - if successful, message "Push notification sent" will be displayed</p>
</li>
<li>
<p dir="auto">Check the push notification on your Android device</p>
</li>
</ul>
<p dir="auto"><strong>NOTE</strong>: Customize the sound, vibration, LED light, and priority of GUI-O app notifications by navigating to "Android settings -&gt; Apps -&gt; Manage apps".</p>
<hr />
<p dir="auto">If you have any questions or run into any problems, please let me know!</p>
<p dir="auto">Best regards,<br />
kl3m3n</p>
]]></description><link>https://forum.gui-o.com/topic/171/episode-21-gui-o-push-notification-from-any-device</link><guid isPermaLink="true">https://forum.gui-o.com/topic/171/episode-21-gui-o-push-notification-from-any-device</guid><dc:creator><![CDATA[kl3m3n]]></dc:creator><pubDate>Tue, 16 Jan 2024 15:43:07 GMT</pubDate></item><item><title><![CDATA[Episode 20: GUI-O and ESP32 with MicroPython]]></title><description><![CDATA[<p dir="auto">ESP32 (and ESP8266) supports MicroPython environment, which enables rapid prototyping due to its ease of use and various built-in modules that offer networking support, hardware control, etc.</p>
<p dir="auto">For examples of GUI-O and ESP32 with MicroPython, please refer to the link below:</p>
<p dir="auto"><a href="https://www.gui-o.com/examples/gui-o-and-boards/esp32-micropython" rel="nofollow ugc">https://www.gui-o.com/examples/gui-o-and-boards/esp32-micropython</a></p>
<hr />
<p dir="auto">If you have any questions or run into any problems, please let me know!</p>
<p dir="auto">Best regards,<br />
kl3m3n</p>
]]></description><link>https://forum.gui-o.com/topic/158/episode-20-gui-o-and-esp32-with-micropython</link><guid isPermaLink="true">https://forum.gui-o.com/topic/158/episode-20-gui-o-and-esp32-with-micropython</guid><dc:creator><![CDATA[kl3m3n]]></dc:creator><pubDate>Sat, 14 Oct 2023 09:07:41 GMT</pubDate></item><item><title><![CDATA[Episode 19: Setup custom MQTT broker for Windows]]></title><description><![CDATA[<p dir="auto">The following tutorial shows how to setup Mosquitto broker on Windows based devices.</p>
<p dir="auto"><strong>Prerequisites</strong></p>
<ul>
<li>OpenSSL software library:</li>
</ul>
<p dir="auto">Download light version <a href="https://slproweb.com/products/Win32OpenSSL.html" rel="nofollow ugc">here</a> and install. Install OpenSSL directly to the main partition (e.g., "C:\OpenSSL-Win64"). When prompted copy DLLs to OpenSSL binaries directory.</p>
<ul>
<li>
<p dir="auto">Access to your router (via IP address using the administrator username and password)</p>
</li>
<li>
<p dir="auto">External (static) IP provided by your internet service provider (ISP)</p>
</li>
<li>
<p dir="auto">GUI-O application version 1.0.47 or higher</p>
</li>
</ul>
<p dir="auto"><strong>IMPORTANT NOTE #1</strong>: It is necessary to ask your ISP for static IP configuration. The certificate in the following steps will be issued for a specific IP. If you do not use static IP configuration, your ISP can change the IP address without notice and the connection to the MQTT broker will not work.</p>
<p dir="auto"><strong>IMPORTANT NOTE #2</strong>: It is generally recommended that a host name is used instead of IP address, but this requires registering the host name with a domain name registrar and setting up some additional settings.</p>
<h3>Step 1: Download and install Mosquitto broker</h3>
<ol>
<li>Download Mosquitto broker <a href="https://mosquitto.org/download/" rel="nofollow ugc">here</a> and perform full installation directly to the main partition (e.g., "C:\mosquitto")</li>
</ol>
<h3>Step 2: Determine your external IP address</h3>
<ol>
<li>Open the command prompt (cmd) and enter the following command:</li>
</ol>
<pre><code>curl ifconfig.me
</code></pre>
<p dir="auto">This will output your external IP, which is needed when issuing the server certificate. You can alternatively navigate to: <a href="https://whatismyipaddress.com/" rel="nofollow ugc">https://whatismyipaddress.com/</a>.</p>
<h3>Step 3: Create self-signed certificate for certificate authority (CA)</h3>
<ol>
<li>Navigate to Mosquitto folder:</li>
</ol>
<pre><code>cd C:\mosquitto
</code></pre>
<ol start="2">
<li>Create a new folder:</li>
</ol>
<pre><code>mkdir certs
</code></pre>
<ol start="3">
<li>Navigate to newly created folder</li>
</ol>
<pre><code>cd certs
</code></pre>
<ol start="4">
<li>Create a private key and CA certificate:</li>
</ol>
<pre><code>C:\OpenSSL-Win64\bin\openssl req -new -x509 -days 365 -extensions v3_ca -keyout ca.key -out ca.crt
</code></pre>
<p dir="auto"><strong>IMPORTANT NOTE</strong>: The "ca.key" file should be kept secure and not shared with anyone.</p>
<p dir="auto">The "days" value is in this case set to 365 (1 year) and denotes the certificate validity. This value can be changed based on your requirements. After the command is executed, you will be prompted to enter a pass phrase and additional certificate information such as country code, state name, city, etc.</p>
<ol start="5">
<li>(Optionally) check the certificate info:</li>
</ol>
<pre><code>C:\OpenSSL-Win64\bin\openssl x509 -noout -text -in ca.crt
</code></pre>
<h3>Step 4: Create a server certificate and sign it with CA</h3>
<ol>
<li>Create "server.cnf" file (you can alternatively download the file <a href="https://drive.google.com/uc?export=download&amp;id=1uwWSGi0QAwhfyD9UPig54XCPPuc_WqDO" rel="nofollow ugc">here</a>) :</li>
</ol>
<pre><code>cd. &gt; server.cnf
</code></pre>
<p dir="auto">Add the following content and replace the "[dn]" and "[alt_names]" sections with your information (use the external IP address obtained in Step 2):</p>
<pre><code>[req]

default_bits = 2048

prompt = no

default_md = sha256

distinguished_name = dn

req_extensions = req_ext


[dn]

C = COUNTRY_CODE_HERE

ST = STATE_HERE

L = CITY_HERE

O = ORGANIZATION_HERE

OU = ORGANIZATION_UNIT_HERE

CN = IP_ADDRESS_HERE


[req_ext]

subjectAltName = @alt_names


[alt_names]

IP.1 = IP_ADDRESS_HERE
</code></pre>
<ol start="2">
<li>Create a private key:</li>
</ol>
<pre><code>C:\OpenSSL-Win64\bin\openssl genrsa -out server.key 2048
</code></pre>
<ol start="3">
<li>Create certificate signing request:</li>
</ol>
<pre><code>C:\OpenSSL-Win64\bin\openssl req -new -key server.key -out server.csr -config server.cnf
</code></pre>
<ol start="4">
<li>Create self-signed certificate using the signing request</li>
</ol>
<pre><code>C:\OpenSSL-Win64\bin\openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 365 -sha256
</code></pre>
<p dir="auto">The "days" value is in this case set to 365 (1 year) and denotes the certificate validity. This value can be changed based on your requirements. After the command is executed, you will be prompted to enter the pass phrase for "ca.key" (this is the pass phrase that was set in Step 3).</p>
<h3>Step 5: Copy the certificate to your Android device</h3>
<ol>
<li>Copy the "ca.crt" to your Android device (e.g., Documents folder), where GUI-O application is installed. You can send the certificate via email, transfer it via USB cable, etc.</li>
</ol>
<h3>Step 6: Setup broker configuration</h3>
<ol>
<li>Use any text editor to open "mosquitto.conf" file located under "C:\mosquitto" (you can alternatively download the file <a href="https://drive.google.com/uc?export=download&amp;id=1wCeeDIc9Jn262K1mnDM3kh6WgQJRTyNs" rel="nofollow ugc">here</a>) :</li>
</ol>
<p dir="auto">Find the "Listeners" section and set:</p>
<pre><code>listener 8883
</code></pre>
<p dir="auto">Find the "Certificate based SSL/TLS support" section and set:</p>
<pre><code>cafile C:\mosquitto\certs\ca.crt

certfile C:\mosquitto\certs\server.crt

keyfile C:\mosquitto\certs\server.key

require_certificate false

use_identity_as_username false

tls_version tlsv1.2
</code></pre>
<p dir="auto">Find the "Security" section and set:</p>
<pre><code>allow_anonymous false

password_file C:\mosquitto\pwfile.example
</code></pre>
<p dir="auto">Save the file.</p>
<ol start="2">
<li>Create user name and password for authentication when connecting to the broker (replace the "USER" and "PASS" with your user name and password - both will be required by the GUI-O application when connecting to the broker):</li>
</ol>
<pre><code>C:\mosquitto\mosquitto_passwd -b C:\mosquitto\pwfile.example USER PASS
</code></pre>
<p dir="auto"><strong>NOTE</strong>: You can add more users with different credentials using this command.</p>
<ol start="3">
<li>
<p dir="auto">Restart Windows</p>
</li>
<li>
<p dir="auto">If the Mosquitto service is not started after the restart, open the cmd as administrator and run:</p>
</li>
</ol>
<pre><code>C:\mosquitto\mosquitto install
</code></pre>
<h3>Step 7: Configure port forwarding rules for your router</h3>
<ol>
<li>Open cmd and determine the MAC (hardware) address of your device, where the Mosquitto broker is running:</li>
</ol>
<pre><code>ipconfig /all
</code></pre>
<p dir="auto">This command will output the MAC address / "Physical Address" (formatted as xx-xx-xx-xx-xx-xx).</p>
<ol start="2">
<li>
<p dir="auto">Open your browser and enter the router IP address into the address bar (the router IP is usually printed on the back of the router). Enter router user name and password when prompted.</p>
</li>
<li>
<p dir="auto">Set a local static IP based on the MAC address of the device. Note that the procedure for setting a local static IP varies depending on the make and model of your router.</p>
</li>
<li>
<p dir="auto">Setup port forwarding by using the local static IP and setting the internal port range from 8883 to 8883 (this is the port that the Mosquitto service is listening on). Set the external port range to any valid value based on your preferences (e.g., from 43520 to 43520). Use TCP protocol and save the settings, making sure that the newly added port forwarding rule is enabled.</p>
</li>
<li>
<p dir="auto">Reboot the router.</p>
</li>
<li>
<p dir="auto">Restart the device, where the Mosquitto broker is running. After the restart, the device should have obtained the local static IP (you can check this by running the "ipconfig" command).</p>
</li>
</ol>
<h3>Step 8: Setup GUI-O application and connect to Mosquitto broker</h3>
<ol>
<li>
<p dir="auto">Open GUI-O application on your Android device and navigate to "Settings -&gt; Connections IoT -&gt; IoT Settings".</p>
</li>
<li>
<p dir="auto">Tap on "Server name" and set the value to your external IP, which was determined in Step 2.</p>
</li>
<li>
<p dir="auto">Tap on "SSL port number" and set the value to your external port number, which was set in Step 7 (e.g., 43520).</p>
</li>
<li>
<p dir="auto">Tap on "User name" and set the user name for authentication, which was created in Step 6.</p>
</li>
<li>
<p dir="auto">Tap on "User password" and set the password for authentication, which was created in Step 6.</p>
</li>
<li>
<p dir="auto">Tap on "Import certificate" and select the "ca.crt", which was transferred to the device in Step 5.</p>
</li>
<li>
<p dir="auto">Return to the previous menu and tap "Connect". If everything was setup correctly, the connection to the Mosquitto broker should be established successfully.</p>
</li>
</ol>
<h3>(Optional) Step 9: Setup ESP32 and connect to Mosquitto broker</h3>
<ol>
<li>
<p dir="auto">Download <a href="https://drive.google.com/uc?export=download&amp;id=16RH9IR5WGR_R-yfHioEyMLrVcMWGGEL3" rel="nofollow ugc">BasicMQTT_Mosquitto.ino</a> sketch and open it in Arduino IDE.</p>
</li>
<li>
<p dir="auto">Open the "ca.crt" file using a text editor and copy / replace the certificate with the one in <a href="https://drive.google.com/uc?export=download&amp;id=16RH9IR5WGR_R-yfHioEyMLrVcMWGGEL3" rel="nofollow ugc">BasicMQTT_Mosquitto.ino</a> source code (keep same certificate formatting)</p>
</li>
<li>
<p dir="auto">Finally, refer to <a href="https://www.gui-o.com/examples/gui-o-and-boards/esp32#h.7e5a31l59xj" rel="nofollow ugc">ESP32 MQTT</a> video example, while using the <a href="https://drive.google.com/uc?export=download&amp;id=16RH9IR5WGR_R-yfHioEyMLrVcMWGGEL3" rel="nofollow ugc">BasicMQTT_Mosquitto.ino</a> sketch. Make sure that the external IP (mqttIP), external port number (mqttPort), user name (mqttUser) and password (mqttPass) variables are set according to Step 8.</p>
</li>
</ol>
<p dir="auto"><strong>NOTE</strong>: Do not forget to generate and set the publish and subscribe topics!</p>
<hr />
<p dir="auto">If you have any questions or run into any problems, please let me know!</p>
<p dir="auto">Best regards,<br />
kl3m3n</p>
]]></description><link>https://forum.gui-o.com/topic/144/episode-19-setup-custom-mqtt-broker-for-windows</link><guid isPermaLink="true">https://forum.gui-o.com/topic/144/episode-19-setup-custom-mqtt-broker-for-windows</guid><dc:creator><![CDATA[kl3m3n]]></dc:creator><pubDate>Sat, 17 Jun 2023 19:45:24 GMT</pubDate></item><item><title><![CDATA[Episode 18: Setup custom MQTT broker for Linux]]></title><description><![CDATA[<p dir="auto">The following tutorial shows how to setup Mosquitto broker on Linux based devices.</p>
<p dir="auto"><strong>Prerequisites:</strong></p>
<ul>
<li>
<p dir="auto">OpenSSL software library (should be preinstalled by default on all Linux distributions)</p>
</li>
<li>
<p dir="auto">Access to your router (via IP address using the administrator username and password)</p>
</li>
<li>
<p dir="auto">External (static) IP provided by your internet service provider (ISP)</p>
</li>
<li>
<p dir="auto">GUI-O application version 1.0.47 or higher</p>
</li>
</ul>
<p dir="auto"><strong>IMPORTANT NOTE #1</strong>: It is necessary to ask your ISP for static IP configuration. The certificate in the following steps will be issued for a specific IP. If you do not use static IP configuration, your ISP can change the IP address without notice and the connection to the MQTT broker will not work.</p>
<p dir="auto"><strong>IMPORTANT NOTE #2</strong>: It is generally recommended that a host name is used instead of IP address, but this requires registering the host name with a domain name registrar and setting up some additional settings.</p>
<h3>Step 1: Install Mosquitto broker</h3>
<ol>
<li>Open the terminal and install Mosquitto broker:</li>
</ol>
<pre><code>sudo apt install mosquitto
</code></pre>
<h3>Step 2: Determine your external IP address</h3>
<ol>
<li>Enter the following command:</li>
</ol>
<pre><code>curl ifconfig.me; echo
</code></pre>
<p dir="auto">This will output your external IP, which is needed when issuing the server certificate. You can alternatively navigate to: <a href="https://whatismyipaddress.com/" rel="nofollow ugc">https://whatismyipaddress.com/</a>.</p>
<h3>Step 3: Create self-signed certificate for certificate authority (CA)</h3>
<ol>
<li>Create a private key and CA certificate:</li>
</ol>
<pre><code>openssl req -new -x509 -days 365 -extensions v3_ca -keyout ca.key -out ca.crt
</code></pre>
<p dir="auto"><strong>IMPORTANT NOTE</strong>: The "ca.key" file should be kept secure and not shared with anyone.</p>
<p dir="auto">The "days" value is in this case set to 365 (1 year) and denotes the certificate validity. This value can be changed based on your requirements. After the command is executed, you will be prompted to enter a pass phrase and additional certificate information such as country code, state name, city, etc.</p>
<ol start="2">
<li>(Optionally) check the certificate info:</li>
</ol>
<pre><code>openssl x509 -noout -text -in ca.crt
</code></pre>
<h3>Step 4: Create a server certificate and sign it with CA</h3>
<ol>
<li>Create "server.cnf" file (you can alternatively download the file <a href="https://drive.google.com/uc?export=download&amp;id=1uwWSGi0QAwhfyD9UPig54XCPPuc_WqDO" rel="nofollow ugc">here</a>) :</li>
</ol>
<pre><code>nano server.cnf
</code></pre>
<p dir="auto">Add the following content and replace the "[dn]" and "[alt_names]" sections with your information (use the external IP address obtained in Step 2):</p>
<pre><code>[req]

default_bits = 2048

prompt = no

default_md = sha256

distinguished_name = dn

req_extensions = req_ext


[dn]

C = COUNTRY_CODE_HERE

ST = STATE_HERE

L = CITY_HERE

O = ORGANIZATION_HERE

OU = ORGANIZATION_UNIT_HERE

CN = IP_ADDRESS_HERE


[req_ext]

subjectAltName = @alt_names


[alt_names]

IP.1 = IP_ADDRESS_HERE
</code></pre>
<p dir="auto"><strong>NOTE</strong>: To save and exit "nano" text editor, press "Ctrl+x", then "y" and "Enter" key.</p>
<ol start="2">
<li>Create a private key:</li>
</ol>
<pre><code>openssl genrsa -out server.key 2048
</code></pre>
<ol start="3">
<li>Create certificate signing request:</li>
</ol>
<pre><code>openssl req -new -key server.key -out server.csr -config server.cnf
</code></pre>
<ol start="4">
<li>Create self-signed certificate using the signing request</li>
</ol>
<pre><code>openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 365 -sha256
</code></pre>
<p dir="auto">The "days" value is in this case set to 365 (1 year) and denotes the certificate validity. This value can be changed based on your requirements. After the command is executed, you will be prompted to enter the pass phrase for "ca.key" (this is the pass phrase that was set in Step 3).</p>
<ol start="5">
<li>Change the permissions for "server.key" file:</li>
</ol>
<pre><code>sudo chmod a+r server.key
</code></pre>
<h3>Step 5: Copy the certificate to your Android device</h3>
<ol>
<li>Copy the "ca.crt" to your Android device (e.g., Documents folder), where GUI-O application is installed. You can send the certificate via email, transfer it via USB cable, etc.</li>
</ol>
<h3>Step 6: Move the files to proper locations</h3>
<ol>
<li>Move the "ca.key" and "ca.crt" file to "/etc/mosquitto/ca_certificates" folder:</li>
</ol>
<pre><code>sudo mv ca.crt ca.key /etc/mosquitto/ca_certificates/
</code></pre>
<ol start="2">
<li>Move the "server.key" and "server.crt" file to "/etc/mosquitto/certs" folder:</li>
</ol>
<pre><code>sudo mv server.crt server.key /etc/mosquitto/certs/
</code></pre>
<h3>Step 7: Setup broker configuration</h3>
<ol>
<li>Create "default.conf" file in "/etc/mosquitto/conf.d" (you can alternatively download the file <a href="https://drive.google.com/uc?export=download&amp;id=1eaAw2VbGleB0vX5fRy8G2goul2k7DgIU" rel="nofollow ugc">here</a>) :</li>
</ol>
<pre><code>sudo nano /etc/mosquitto/conf.d/default.conf
</code></pre>
<p dir="auto">Add the following content:</p>
<pre><code># Listener

listener 8883

cafile /etc/mosquitto/ca_certificates/ca.crt

certfile /etc/mosquitto/certs/server.crt

keyfile /etc/mosquitto/certs/server.key

require_certificate false

use_identity_as_username false


# TLS

tls_version tlsv1.2


# Security

allow_anonymous false

password_file /etc/mosquitto/passwd


# Logging

#log_type error

#log_type warning

log_type all
</code></pre>
<p dir="auto"><strong>NOTE</strong>: To save and exit "nano" text editor, press "Ctrl+x", then "y" and "Enter" key.</p>
<ol start="2">
<li>Create user name and password for authentication when connecting to the broker (replace the "USER" and "PASS" with your user name and password - both will be required by the GUI-O application when connecting to the broker):</li>
</ol>
<pre><code>sudo mosquitto_passwd -b /etc/mosquitto/passwd USER PASS
</code></pre>
<p dir="auto"><strong>NOTE</strong>: You can add more users with different credentials using this command.</p>
<ol start="3">
<li>Restart the Mosquitto service:</li>
</ol>
<pre><code>sudo systemctl restart mosquitto.service
</code></pre>
<ol start="4">
<li>(Optionally) check the status of the Mosquitto service:</li>
</ol>
<pre><code>sudo systemctl status mosquitto.service
</code></pre>
<h3>Step 8: Configure port forwarding rules for your router</h3>
<ol>
<li>Determine the MAC (hardware) address of your device, where the Mosquitto broker is running:</li>
</ol>
<pre><code>ifconfig
</code></pre>
<p dir="auto">This command will output the MAC address after the "ether" keyword (formatted as xx:xx:xx:xx:xx:xx).</p>
<ol start="2">
<li>
<p dir="auto">Open your browser and enter the router IP address into the address bar (the router IP is usually printed on the back of the router). Enter router user name and password when prompted.</p>
</li>
<li>
<p dir="auto">Set a local static IP based on the MAC address of the device. Note that the procedure for setting a local static IP varies depending on the make and model of your router.</p>
</li>
<li>
<p dir="auto">Setup port forwarding by using the local static IP and setting the internal port range from 8883 to 8883 (this is the port that the Mosquitto service is listening on). Set the external port range to any valid value based on your preferences (e.g., from 43519 to 43519). Use TCP protocol and save the settings, making sure that the newly added port forwarding rule is enabled.</p>
</li>
<li>
<p dir="auto">Reboot the router.</p>
</li>
<li>
<p dir="auto">Restart the device, where the Mosquitto broker is running. After the restart, the device should have obtained the local static IP (you can check this by running the "ifconfig" command).</p>
</li>
</ol>
<h3>Step 9: Setup GUI-O application and connect to Mosquitto broker</h3>
<ol>
<li>
<p dir="auto">Open GUI-O application on your Android device and navigate to "Settings -&gt; Connections IoT -&gt; IoT Settings".</p>
</li>
<li>
<p dir="auto">Tap on "Server name" and set the value to your external IP, which was determined in Step 2.</p>
</li>
<li>
<p dir="auto">Tap on "SSL port number" and set the value to your external port number, which was set in Step 8 (e.g., 43519).</p>
</li>
<li>
<p dir="auto">Tap on "User name" and set the user name for authentication, which was created in Step 7.</p>
</li>
<li>
<p dir="auto">Tap on "User password" and set the password for authentication, which was created in Step 7.</p>
</li>
<li>
<p dir="auto">Tap on "Import certificate" and select the "ca.crt", which was transferred to the device in Step 5.</p>
</li>
<li>
<p dir="auto">Return to the previous menu and tap "Connect". If everything was setup correctly, the connection to the Mosquitto broker should be established successfully.</p>
</li>
</ol>
<h3>(Optional) Step 10: Setup ESP32 and connect to Mosquitto broker</h3>
<ol>
<li>
<p dir="auto">Download <a href="https://drive.google.com/uc?export=download&amp;id=16RH9IR5WGR_R-yfHioEyMLrVcMWGGEL3" rel="nofollow ugc">BasicMQTT_Mosquitto.ino</a> sketch and open it in Arduino IDE.</p>
</li>
<li>
<p dir="auto">Get the "ca.crt" data in plain text format. Open the terminal on the device where the Mosquitto broker is running and run the following command:</p>
</li>
</ol>
<pre><code>cat /etc/mosquitto/ca_certificates/ca.crt
</code></pre>
<p dir="auto">Copy the certificate displayed in the terminal and replace the one in <a href="https://drive.google.com/uc?export=download&amp;id=16RH9IR5WGR_R-yfHioEyMLrVcMWGGEL3" rel="nofollow ugc">BasicMQTT_Mosquitto.ino</a> source code (keep same certificate formatting).</p>
<ol start="3">
<li>Finally, refer to <a href="https://www.gui-o.com/examples/gui-o-and-boards/esp32#h.7e5a31l59xj" rel="nofollow ugc">ESP32 MQTT</a> video example, while using the <a href="https://drive.google.com/uc?export=download&amp;id=16RH9IR5WGR_R-yfHioEyMLrVcMWGGEL3" rel="nofollow ugc">BasicMQTT_Mosquitto.ino</a> sketch. Make sure that the external IP (mqttIP), external port number (mqttPort), user name (mqttUser) and password (mqttPass) variables are set according to Step 9.</li>
</ol>
<p dir="auto"><strong>NOTE</strong>: Do not forget to generate and set the publish and subscribe topics!</p>
<hr />
<p dir="auto">If you have any questions or run into any problems, please let me know!</p>
<p dir="auto">Best regards,<br />
kl3m3n</p>
]]></description><link>https://forum.gui-o.com/topic/143/episode-18-setup-custom-mqtt-broker-for-linux</link><guid isPermaLink="true">https://forum.gui-o.com/topic/143/episode-18-setup-custom-mqtt-broker-for-linux</guid><dc:creator><![CDATA[kl3m3n]]></dc:creator><pubDate>Sat, 17 Jun 2023 19:29:12 GMT</pubDate></item><item><title><![CDATA[Episode 17: URL image stream]]></title><description><![CDATA[<p dir="auto">This example shows how to obtain IP camera snapshots (via url request) and update image widget to produce continuous image stream.</p>
<p dir="auto"><strong>NOTE</strong>: GUI-O application v1.0.47 fixes image "flickering" bug.</p>
<p dir="auto"><strong>I will be using GUI-O Bluetooth Low Energy (LE) connection, but the example can be easily ported to other connection types.</strong></p>
<p dir="auto"><strong>Software prerequisites:</strong></p>
<ul>
<li>
<p dir="auto">Arduino IDE (<a href="https://www.arduino.cc/en/software" rel="nofollow ugc">https://www.arduino.cc/en/software</a>)</p>
</li>
<li>
<p dir="auto">ESP32 Arduino board support, if using ESP32 based board (see <a href="https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html" rel="nofollow ugc">https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html</a>)</p>
</li>
<li>
<p dir="auto">GUI-O application (<a href="https://play.google.com/store/apps/details?id=com.guio.guioapp" rel="nofollow ugc">https://play.google.com/store/apps/details?id=com.guio.guioapp</a>)</p>
</li>
<li>
<p dir="auto">For additional information about the GUI-O application, download the developer manual from <a href="https://www.gui-o.com/" rel="nofollow ugc">https://www.gui-o.com/</a></p>
</li>
</ul>
<p dir="auto"><strong>Components needed:</strong></p>
<ul>
<li>ESP32-WROOM-32 (or any other Arduino supported Bluetooth Low Energy capable board)</li>
</ul>
<p dir="auto"><strong>The entire tutorial is split into various steps. All necessary information is given in each step</strong>.</p>
<h3>0. DESIGN THE GUI (optional)</h3>
<p dir="auto">The best way to create a GUI layout is to use <a href="https://www.gui-o.com/design-tool" rel="nofollow ugc">GUI-O live designer tool</a>. Please check previous episodes to see how to use the designer tool.</p>
<h3>1. UPLOAD THE SOURCE CODE</h3>
<p dir="auto">The source code has inline comments, describing the important parts of the code. You can copy the source code from the snippet below, or download it <a href="https://drive.google.com/uc?export=download&amp;id=13-KwePKAT3P7wHzOVhNG70fYmQoDxrEh" rel="nofollow ugc">here</a>.</p>
<p dir="auto">Upload the code to your board (make sure that the correct board and upload port are selected). Reset the board after upload.</p>
<pre><code>/*
 * GUI-O Image Stream Bluetooth example (using ESP32-WROOM-32)
 *
 * Copyright (C) 2023, kl3m3n
 * last updated on 28.05.2023
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include &lt;BLEDevice.h&gt;
#include &lt;BLEServer.h&gt;
#include &lt;BLEUtils.h&gt;
#include &lt;BLE2902.h&gt;

namespace uuid {
  static const char *SERVICE_UUID = "6E400001-B5A3-F393-E0A9-E50E24DCCA9E";
  static const char *RX_CHARACTERISTIC_UUID = "6E400002-B5A3-F393-E0A9-E50E24DCCA9E";
  static const char *TX_CHARACTERISTIC_UUID = "6E400003-B5A3-F393-E0A9-E50E24DCCA9E";
} // namespace uuid

// forward declare parser for incoming messages
void parseGuioMsg(const String &amp;msg);

// setup done flag
bool setupDone = false;

// custom handling of server callbacks
class CustomBLEServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
      Serial.println("Connected!");
    };
    void onDisconnect(BLEServer* pServer) {
      Serial.println("Disconnected!");
      
      // restart advertising after disconnect, otherwise GUI-O cannot re-connect
      if(setupDone) {
        // restart advertising on disconnect
        delay(500);
        pServer-&gt;startAdvertising(); 
      }
    }
};

// custom handling of characteristic callbacks
class CustomBLECharacteristicCallbacks: public BLECharacteristicCallbacks {
  void onWrite(BLECharacteristic *pCharacteristic) {
    std::string msg = pCharacteristic-&gt;getValue();
    
    // parse message string
    parseGuioMsg(String(msg.c_str()));
  }      
};

// global ptr
BLECharacteristic *pTxCharacteristic;

bool stream;
unsigned long startTimestampMsec, currentTimestampMsec;
const unsigned long updateIntervalMsec = 1000; // milliseconds

void setup() {
  // debug output
  Serial.begin(115200);

  // create device
  BLEDevice::init("ImageStream");
  // create server and register callback
  BLEServer *pServer = BLEDevice::createServer();
  pServer-&gt;setCallbacks(new CustomBLEServerCallbacks());
  // create service
  BLEService *pService = pServer-&gt;createService(uuid::SERVICE_UUID);

  // crate Tx characteristic and add descriptor
  pTxCharacteristic = pService-&gt;createCharacteristic(uuid::TX_CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_NOTIFY);
  pTxCharacteristic-&gt;addDescriptor(new BLE2902());
  
  // crate Rx characteristic and register callback
  BLECharacteristic *pRxCharacteristic = pService-&gt;createCharacteristic(uuid::RX_CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_WRITE_NR);
  pRxCharacteristic-&gt;setCallbacks(new CustomBLECharacteristicCallbacks());

  // start the service and start advertising
  pService-&gt;start();
  pServer-&gt;getAdvertising()-&gt;start();

  // setup done flag
  setupDone = true;
}

void loop() {
  currentTimestampMsec = millis();
  if(currentTimestampMsec - startTimestampMsec &gt; updateIntervalMsec) {
    if(stream)
      sendMsg("@im IP:\"https://kamere.dars.si/kamere/Kozina/Dilce_2.jpg\"\r\n");
    // reset read interval
    startTimestampMsec = millis();
  }  
}

void sendMsg(const String &amp;msg) {
  pTxCharacteristic-&gt;setValue(std::string(msg.c_str()));
  pTxCharacteristic-&gt;notify();
  delay(50);
}

void parseGuioMsg(const String &amp;msg) {
  if(msg.startsWith("@init")) {
    Serial.println("GUI-O app is requesting INITIALIZATION!");

    // clear screen and set background
    sendMsg("@cls\r\n");
    sendMsg("@guis BGC:#FFFFFF\r\n");
    delay(100);

    // initialize GUI
    sendMsg("|LB UID:title X:50 Y:20 FSZ:4 FFA:\"font8\" TXT:\"Image&lt;br&gt;stream\"\r\n");
    sendMsg("|IM UID:im X:50 Y:50 W:80 FURL:1 IP:\"https://kamere.dars.si/kamere/Kozina/Dilce_2.jpg\"\r\n");
    sendMsg("|TG UID:tg X:50 Y:75 EN:1\r\n");
    sendMsg("|LB UID:details X:50 Y:90 FSZ:2 TXT:\"GUI-O image stream&lt;br&gt;demonstration by kl3m3n\"\r\n");

    // defaults to true (tg has property EN set to true)
    stream = true;
  }
  else if(msg.startsWith("@tg"))
    stream = (msg.indexOf("1") &gt; 0);
}
</code></pre>
<h3>2. ESTABLISH CONNECTION</h3>
<p dir="auto">Open GUI-O application and press <strong>Add</strong> in the upper-right corner of the home screen. Tap on <strong>Bluetooth LE</strong> and search for devices (enable Bluetooth and Location services, if prompted). Tap on the "ImageStream" device and wait for successful connection (confirm device pairing if prompted).</p>
<p dir="auto">Close the settings menu and press the <strong>Initialize</strong> button (see image below) from the GUI-O application home screen.</p>
<p dir="auto"><img src="https://i.imgur.com/DDEHAR7l.jpg" alt="initialize_button.jpg" class=" img-fluid img-markdown" /></p>
<h3>3. THE RESULT</h3>
<p dir="auto">Image below shows the result (screen capture) on my Android device after pressing the "Initialize" button. The image stream is enabled by default and can be disabled by tapping on the toggle widget.</p>
<p dir="auto"><img src="https://i.imgur.com/M6SJnVLl.jpg" alt="screen.jpg" class=" img-fluid img-markdown" /></p>
<hr />
<p dir="auto">If you have any questions or run into any problems, please let me know!</p>
<p dir="auto">Best regards,<br />
kl3m3n</p>
]]></description><link>https://forum.gui-o.com/topic/140/episode-17-url-image-stream</link><guid isPermaLink="true">https://forum.gui-o.com/topic/140/episode-17-url-image-stream</guid><dc:creator><![CDATA[kl3m3n]]></dc:creator><pubDate>Wed, 31 May 2023 10:09:50 GMT</pubDate></item><item><title><![CDATA[Episode 16: Initializing GUI from file]]></title><description><![CDATA[<p dir="auto">This episode shows how to use GUI-O design tool to create GUI initialization commands and transfer them to Android device (where they are stored in a file). GUI-O application can then read and parse the initialization file upon external request from MCU, PC, etc.</p>
<hr />
<h4><strong>NOTE:</strong> This example requires PRO version of GUI-O application. Don't worry, you can still do lots of other great things using free DEMO version of GUI-O!</h4>
<hr />
<p dir="auto"><strong>Software prerequisites:</strong></p>
<ul>
<li>
<p dir="auto">GUI-O design tool (<a href="https://www.gui-o.com/design-tool" rel="nofollow ugc">https://www.gui-o.com/design-tool</a>)</p>
</li>
<li>
<p dir="auto">GUI-O application (<a href="https://play.google.com/store/apps/details?id=com.guio.guioapp" rel="nofollow ugc">https://play.google.com/store/apps/details?id=com.guio.guioapp</a>)</p>
</li>
<li>
<p dir="auto">For additional information about the GUI-O application, download the developer manual from <a href="https://www.gui-o.com/" rel="nofollow ugc">https://www.gui-o.com/</a></p>
</li>
</ul>
<h3>1. CONFIGURE GUI-O DESIGN TOOL</h3>
<p dir="auto">In this example, I will be using TCP/IP connection, but the design tool also supports USB connection. In case of TCP/IP connection, make sure you are connected to the same local network.</p>
<ol>
<li>Determine the local IP address of your PC's network interface (WiFi or Ethernet):</li>
</ol>
<ul>
<li>Under Windows, open the command prompt, enter <code>ipconfig</code> and press Enter</li>
<li>Under Linux, open the terminal, enter <code>ifconfig</code> and press Enter</li>
</ul>
<ol start="2">
<li>
<p dir="auto">Open GUI-O designer and select "TCP/IP connection" tab. Set the IP address and any port number between 49152 - 65535. Click "Start server" button.</p>
</li>
<li>
<p dir="auto">Open GUI-O application and tap "Add" located at the upper-right part of the screen. Tap "Etherned" and add a new device using the same IP address and port. Tap on the created device and wait for successful connection with GUI-O design tool.</p>
</li>
</ol>
<h3>2. CREATE WIDGETS</h3>
<p dir="auto">Create various widgets and observe (and interact with) them in real-time on your Android device. Modify the properties of the widgets based on your preferences.</p>
<h3>3. TRANSFER INITIALIZATION COMMANDS</h3>
<p dir="auto">Send the initialization commands for the created widgets to your Android device, where they are stored in a file that can be parsed "on-demand" by the GUI-O application.</p>
<ol>
<li>
<p dir="auto">Select "Transfer to device" tab.</p>
</li>
<li>
<p dir="auto">Specify the file name and press "Enter" or click on "Start transfer" button. Wait for the transfer to complete.</p>
</li>
</ol>
<p dir="auto">After the transfer is successfully completed, the initialization commands are located in a file on your Android device. You can test this by navigating to "Send command" tab.</p>
<p dir="auto">First, clear the GUI by sending <strong>@cls</strong> command. Then send the command <strong>@fileinit FNA:"&lt;filename&gt;"</strong>, where <strong>&lt;filename&gt;</strong> parameter denotes the full name of the file during commands transfer phase.</p>
<h3>4. VIDEO TUTORIAL</h3>
<p dir="auto">The video tutorial for all steps is shown below.</p>
<p dir="auto"></p><div class="video-embed"><iframe allowfullscreen src="//www.youtube.com/embed/My6mVIDl1tw"></iframe></div><p></p>
<hr />
<p dir="auto">If you have any questions or run into any problems, please let me know!</p>
<p dir="auto">Best regards,<br />
kl3m3n</p>
]]></description><link>https://forum.gui-o.com/topic/139/episode-16-initializing-gui-from-file</link><guid isPermaLink="true">https://forum.gui-o.com/topic/139/episode-16-initializing-gui-from-file</guid><dc:creator><![CDATA[kl3m3n]]></dc:creator><pubDate>Thu, 18 May 2023 07:56:50 GMT</pubDate></item><item><title><![CDATA[Episode 15: Switching screens]]></title><description><![CDATA[<p dir="auto">This example shows how to use multiple GUI-O screens and switch between them.</p>
<p dir="auto">GUI-O supports up to five (5) screens, where widgets can be placed.</p>
<p dir="auto">Switching between screens can be performed in two ways: using the <strong>1. built-in flick functionality</strong> or by creating a <strong>2. flick area widget (FLA)</strong> and reacting to user input on the ESP32 side.<br />
Here, I will only cover only the first option. For the second option, see the GUI-O developer manual (hint: see section <strong>Multiple screen support</strong>).</p>
<p dir="auto"><strong>I will be using GUI-O Bluetooth Low Energy (LE) connection, but the example can be easily be ported to other connection types.</strong></p>
<p dir="auto"><strong>Software prerequisites:</strong></p>
<ul>
<li>
<p dir="auto">Arduino IDE (<a href="https://www.arduino.cc/en/software" rel="nofollow ugc">https://www.arduino.cc/en/software</a>)</p>
</li>
<li>
<p dir="auto">ESP32 Arduino board support, if using ESP32 based board (see <a href="https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html" rel="nofollow ugc">https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html</a>)</p>
</li>
<li>
<p dir="auto">GUI-O design tool (<a href="https://www.gui-o.com/design-tool" rel="nofollow ugc">https://www.gui-o.com/design-tool</a>)</p>
</li>
<li>
<p dir="auto">GUI-O application (<a href="https://play.google.com/store/apps/details?id=com.guio.guioapp" rel="nofollow ugc">https://play.google.com/store/apps/details?id=com.guio.guioapp</a>)</p>
</li>
<li>
<p dir="auto">For additional information about the GUI-O application, download the developer manual from <a href="https://www.gui-o.com/" rel="nofollow ugc">https://www.gui-o.com/</a></p>
</li>
</ul>
<p dir="auto"><strong>Components needed:</strong></p>
<ul>
<li>ESP32-WROOM-32 (or any other Arduino supported Bluetooth Low Energy capable board)</li>
</ul>
<p dir="auto"><strong>The entire tutorial is split into various steps. All necessary information is given in each step</strong>.</p>
<h3>0. DESIGN THE GUI (optional)</h3>
<p dir="auto">The best way to create a GUI layout is to use GUI-O live designer tool.</p>
<p dir="auto">Note that the Arduino source code already includes the necessary commands, so this step is not needed, unless you want to make some visual adjustments. If you make adjustments, please include the generated ASCII code in the Arduino source code (see section 1. UPLOAD THE SOURCE CODE).</p>
<p dir="auto">First, you need to establish a TCP/IP connection between the designer tool and GUI-O application:</p>
<ol>
<li>Determine the local IP address of your PC's network interface (WiFi or Ethernet)</li>
</ol>
<ul>
<li>Under Windows, open the command prompt, enter <code>ipconfig</code> and press Enter</li>
<li>Under Linux, open the terminal, enter <code>ifconfig</code> and press Enter</li>
</ul>
<ol start="2">
<li>
<p dir="auto">Open GUI-O application and open settings menu. Select "Connections -&gt; Ethernet" and create a new device with IP address (determined from 1.) and any port between 49152 - 65535</p>
</li>
<li>
<p dir="auto">Open GUI-O designer and select "TCP/IP connection" tab. Set the IP address and port. Both values must match the device settings created within the GUI-O application. Click "Start server" button.</p>
</li>
<li>
<p dir="auto">Within the GUI-O application, tap the created device and wait for successful connection.</p>
</li>
<li>
<p dir="auto">In the GUI-O designer, select "File -&gt; Load designer file" and load the <a href="https://drive.google.com/uc?export=download&amp;id=1Wibvm1KOTWrDJcXaZLgwXUd9DX0DB3bm" rel="nofollow ugc">SwitchScreen.gdf</a> design file. Make the desired adjustments, if necessary. Copy / replace the GUI-O commands into the Arduino source code (see section 1. UPLOAD THE SOURCE CODE).</p>
</li>
</ol>
<h3>1. UPLOAD THE SOURCE CODE</h3>
<p dir="auto">The source code has inline comments, describing the important parts of the code. You can copy the source code from the snippet below, or download it <a href="https://drive.google.com/uc?export=download&amp;id=1NR_U0IxjOKxjA1hndTNsFEuczgZrUM4a" rel="nofollow ugc">here</a>.</p>
<p dir="auto">Upload the code to your board (make sure that the correct board and upload port are selected). Reset the board after upload.</p>
<pre><code>/*
 * GUI-O Switch screen Bluetooth example (using ESP32-WROOM-32)
 *
 * Copyright (C) 2023, kl3m3n
 * last updated on 01.04.2023
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include &lt;BLEDevice.h&gt;
#include &lt;BLEServer.h&gt;
#include &lt;BLEUtils.h&gt;
#include &lt;BLE2902.h&gt;

namespace uuid {
  static const char *SERVICE_UUID = "6E400001-B5A3-F393-E0A9-E50E24DCCA9E";
  static const char *RX_CHARACTERISTIC_UUID = "6E400002-B5A3-F393-E0A9-E50E24DCCA9E";
  static const char *TX_CHARACTERISTIC_UUID = "6E400003-B5A3-F393-E0A9-E50E24DCCA9E";
} // namespace uuid

// forward declare parser for incoming messages
void parseGuioMsg(const String &amp;msg);

// setup done flag
bool setupDone = false;

// custom handling of server callbacks
class CustomBLEServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
      Serial.println("Connected!");
    };
    void onDisconnect(BLEServer* pServer) {
      Serial.println("Disconnected!");
      
      // restart advertising after disconnect, otherwise GUI-O cannot re-connect
      if(setupDone) {
        // restart advertising on disconnect
        delay(500);
        pServer-&gt;startAdvertising(); 
      }
    }
};

// custom handling of characteristic callbacks
class CustomBLECharacteristicCallbacks: public BLECharacteristicCallbacks {
  void onWrite(BLECharacteristic *pCharacteristic) {
    std::string msg = pCharacteristic-&gt;getValue();
    
    // parse message string
    parseGuioMsg(String(msg.c_str()));
  }      
};

// global ptr
BLECharacteristic *pTxCharacteristic;

void setup() {
  // debug output
  Serial.begin(115200);

  // create device
  BLEDevice::init("SwitchScreen");
  // create server and register callback
  BLEServer *pServer = BLEDevice::createServer();
  pServer-&gt;setCallbacks(new CustomBLEServerCallbacks());
  // create service
  BLEService *pService = pServer-&gt;createService(uuid::SERVICE_UUID);

  // crate Tx characteristic and add descriptor
  pTxCharacteristic = pService-&gt;createCharacteristic(uuid::TX_CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_NOTIFY);
  pTxCharacteristic-&gt;addDescriptor(new BLE2902());
  
  // crate Rx characteristic and register callback
  BLECharacteristic *pRxCharacteristic = pService-&gt;createCharacteristic(uuid::RX_CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_WRITE_NR);
  pRxCharacteristic-&gt;setCallbacks(new CustomBLECharacteristicCallbacks());

  // start the service and start advertising
  pService-&gt;start();
  pServer-&gt;getAdvertising()-&gt;start();

  // setup done flag
  setupDone = true;
}

void loop() {
  
}

void sendMsg(const String &amp;msg) {
  pTxCharacteristic-&gt;setValue(std::string(msg.c_str()));
  pTxCharacteristic-&gt;notify();
  delay(50);
}

void parseGuioMsg(const String &amp;msg) {
  if(msg.startsWith("@init")) {
    Serial.println("GUI-O app is requesting INITIALIZATION!");

    // clear screen and set background
    sendMsg("@cls\r\n");
    sendMsg("@guis BGC:#FFFFFF PGF:1\r\n");
    delay(100);

    // initialize GUI
    sendMsg("|LB UID:title X:50 Y:20 FSZ:4 FFA:\"font8\" TXT:\"Switch&lt;br&gt;screen\"\r\n");
    sendMsg("|LB UID:home X:50 Y:50 FGC:#607196 SHE:1 SHC:#FFC759 FSZ:5 FFA:\"font1\" TXT:\"HOME SCREEN\"\r\n");
    sendMsg("|LB UID:screen1 X:50 Y:50 FGC:#607196 SHE:1 SHC:#FFC759 FSZ:5 FFA:\"font1\" TXT:\"SCREEN 1\" SCI:1\r\n");
    sendMsg("|LB UID:screen2 X:50 Y:50 FGC:#607196 SHE:1 SHC:#FFC759 FSZ:5 FFA:\"font1\" TXT:\"SCREEN 2\" SCI:2\r\n");
    sendMsg("|LB UID:screen3 X:50 Y:50 FGC:#607196 SHE:1 SHC:#FFC759 FSZ:5 FFA:\"font1\" TXT:\"SCREEN 3 ...\" SCI:3\r\n");
    sendMsg("|LB UID:details X:50 Y:90 FSZ:2 TXT:\"GUI-O switch screen&lt;br&gt;demonstration by kl3m3n\"\r\n");    
  }
}
</code></pre>
<h3>2. ESTABLISH CONNECTION</h3>
<p dir="auto">Open GUI-O application and press <strong>Add</strong> in the upper-right corner of the home screen. Tap on <strong>Bluetooth LE</strong> and search for devices (enable Bluetooth and Location services, if prompted). Tap on the "SwitchScreen" device, select <strong>Nordic UART service</strong> and wait for successful connection (confirm device pairing if prompted).</p>
<p dir="auto">Close the settings menu and press the <strong>Initialize</strong> button (see image below) from the GUI-O application home screen.</p>
<p dir="auto"><img src="https://i.imgur.com/DDEHAR7l.jpg" alt="initialize_button.jpg" class=" img-fluid img-markdown" /></p>
<h3>3. THE RESULT</h3>
<p dir="auto">Image below shows the result (screen capture) on my Android device after pressing the "Initialize" button. The bottom screen indicator indicates the number of screens and the currently active screen. Navigation between screens is possible by flicking left or right at the bottom of the screen. This is shown in the video below.</p>
<p dir="auto"><img src="https://i.imgur.com/3wqnmKql.jpg" alt="screen.jpg" class=" img-fluid img-markdown" /></p>
<p dir="auto"></p><div class="video-embed"><iframe allowfullscreen src="//www.youtube.com/embed/pbN5Mbvrk7U"></iframe></div><p></p>
<hr />
<p dir="auto">If you have any questions or run into any problems, please let me know!</p>
<p dir="auto">Best regards,<br />
kl3m3n</p>
]]></description><link>https://forum.gui-o.com/topic/128/episode-15-switching-screens</link><guid isPermaLink="true">https://forum.gui-o.com/topic/128/episode-15-switching-screens</guid><dc:creator><![CDATA[kl3m3n]]></dc:creator><pubDate>Sat, 01 Apr 2023 10:03:50 GMT</pubDate></item><item><title><![CDATA[Episode 14: Saving data to Android device]]></title><description><![CDATA[<p dir="auto">This episode shows how various data (sensor readings, user input, etc.) can be stored to the Android device. Furthermore, the stored data can then be read, opened or shared.</p>
<hr />
<h4><strong>NOTE:</strong> This example requires PRO version of GUI-O application. Don't worry, you can still do lots of other great things using free DEMO version of GUI-O <img src="https://forum.gui-o.com/assets/plugins/nodebb-plugin-emoji/emoji/android/1f642.png?v=29eca934c85" class="not-responsive emoji emoji-android emoji--slightly_smiling_face" style="height:23px;width:auto;vertical-align:middle" title=":)" alt="🙂" /> !</h4>
<hr />
<p dir="auto"><strong>I will be using GUI-O IoT (MQTT) connection, but the example can be easily be ported to other connection types (Bluetooth, BLE, USB...).</strong></p>
<p dir="auto"><strong>Software prerequisites:</strong></p>
<ul>
<li>
<p dir="auto">Arduino IDE (<a href="https://www.arduino.cc/en/software" rel="nofollow ugc">https://www.arduino.cc/en/software</a>)</p>
</li>
<li>
<p dir="auto">ESP32 Arduino board support, if using ESP32 based board (see <a href="https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html" rel="nofollow ugc">https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html</a>)</p>
</li>
<li>
<p dir="auto">Arduino Client for MQTT(<a href="https://github.com/knolleary/pubsubclient" rel="nofollow ugc">https://github.com/knolleary/pubsubclient</a>)<br />
You can follow the setup instructions or directly download and include the <strong><a href="https://drive.google.com/uc?export=download&amp;id=1yRJCDFR2xQDodyIA_lqKfcYdU6pAFy1C" rel="nofollow ugc">PubSubClient.zip</a></strong> library within the Arduino IDE (Sketch -&gt; Include Library -&gt; Add .ZIP library)</p>
</li>
<li>
<p dir="auto">GUI-O design tool (<a href="https://www.gui-o.com/design-tool" rel="nofollow ugc">https://www.gui-o.com/design-tool</a>)</p>
</li>
<li>
<p dir="auto">GUI-O application (<a href="https://play.google.com/store/apps/details?id=com.guio.guioapp" rel="nofollow ugc">https://play.google.com/store/apps/details?id=com.guio.guioapp</a>)</p>
</li>
<li>
<p dir="auto">For additional information about the GUI-O application, download the developer manual from <a href="https://www.gui-o.com/" rel="nofollow ugc">https://www.gui-o.com/</a></p>
</li>
</ul>
<p dir="auto"><strong>Components needed:</strong></p>
<ul>
<li>ESP32-WROOM-32 (or any other Arduino supported WiFi capable board; see <a href="https://github.com/knolleary/pubsubclient#compatible-hardware" rel="nofollow ugc">https://github.com/knolleary/pubsubclient#compatible-hardware</a> for compatible hardware)</li>
</ul>
<p dir="auto"><strong>The entire tutorial is split into various steps. All necessary information is given in each step</strong>.</p>
<h3>0. DESIGN THE GUI (optional)</h3>
<p dir="auto">The best way to create a GUI layout is to use GUI-O live designer tool.</p>
<p dir="auto">Note that the Arduino source code already includes the necessary commands, so this step is not needed, unless you want to make some visual adjustments. If you make adjustments, please include the generated ASCII code in the Arduino source code (see section 3. MODIFY AND UPLOAD THE SOURCE CODE).</p>
<p dir="auto">First, you need to establish a TCP/IP connection between the designer tool and GUI-O application:</p>
<ol>
<li>Determine the local IP address of your PC's network interface (WiFi or Ethernet)</li>
</ol>
<ul>
<li>Under Windows, open the command prompt, enter <code>ipconfig</code> and press Enter</li>
<li>Under Linux, open the terminal, enter <code>ifconfig</code> and press Enter</li>
</ul>
<ol start="2">
<li>
<p dir="auto">Open GUI-O application and open settings menu. Select "Connections -&gt; Ethernet" and create a new device with IP address (determined from 1.) and any port between 49152 - 65535</p>
</li>
<li>
<p dir="auto">Open GUI-O designer and select "TCP/IP connection" tab. Set the IP address and port. Both values must match the device settings created within the GUI-O application. Click "Start server" button.</p>
</li>
<li>
<p dir="auto">Within the GUI-O application, tap the created device and wait for successful connection.</p>
</li>
<li>
<p dir="auto">In the GUI-O designer, select "File -&gt; Load designer file" and load the <a href="https://drive.google.com/uc?export=download&amp;id=1427ZMIKPYi4o6FskdqQhrNZns8UmSouW" rel="nofollow ugc">SavingData.gdf</a> design file. Make the desired adjustments, if necessary. Copy / replace the GUI-O commands into the Arduino source code (see section 2. MODIFY AND UPLOAD THE SOURCE CODE).</p>
</li>
</ol>
<h3>1. CREATE A UNIQUE MQTT CHANNEL</h3>
<p dir="auto">Open GUI-O application and press <strong>Add</strong> from home screen (top-right corner of the display). Select "IoT (Create device)" and add a new device. After adding the device, note the <strong>In</strong> and <strong>Out</strong> token (you can share this tokens e.g., to your e-mail by pressing the "share" button).</p>
<p dir="auto">Finally, press "Connect" menu entry to establish the connection with the MQTT server.</p>
<h3>2. MODIFY AND UPLOAD THE SOURCE CODE</h3>
<p dir="auto">The source code has inline comments, describing the important parts of the code. You can copy the source code from the snippet below, or download it <a href="https://drive.google.com/uc?export=download&amp;id=1s5nWr-iMLX75vLyheQE24fLF18-NLlAb" rel="nofollow ugc">here</a>.</p>
<p dir="auto">The only thing that needs to be done is to set the <strong>ssid</strong> and <strong>password</strong> of your router and the unique <strong>In</strong> and <strong>Out</strong> channels that were generated by the GUI-O application (see section 1. CREATE A UNIQUE MQTT CHANNEL).</p>
<p dir="auto">After setting these values, upload the code to your board (make sure that the correct board and upload port are selected). Reset the board after upload.</p>
<pre><code>/*
 * GUI-O Saving Data MQTT example (using ESP32-WROOM-32)
 *
 * Copyright (C) 2023, kl3m3n
 * last updated on 11.3.2023
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include &lt;WiFi.h&gt;
#include &lt;PubSubClient.h&gt;
#include &lt;string&gt;

#define DEBUG(title, payload) \
  Serial.print(title); \
  Serial.println(payload); \

static const char *ssid = "&lt;ssid&gt;"; // router name
static const char *pass = "&lt;pass&gt;"; // router password

static const char *mqttServer = "mqtt.gui-o.com";   // host name
static const char *mqttUser = "gui-o-mqtt-generic"; // user name
static const char *mqttPass = "lqXeZpv5VJyv0XBT";   // password

// IMPORTANT NOTE: if optional user name was specified when adding a new IoT device,
// the user name should also be included when setting the topics (e.g., "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/&lt;user_name&gt;")
static const char *Out = "&lt;Out&gt;"; // GUI-O app publish topic
static const char *In = "&lt;In&gt;";  // GUI-O app subscribe topic

// mqtt client
WiFiClient wiFiClient;
PubSubClient mqttClient(wiFiClient);

// forward declare functions for mqtt messages handling
void mqttCallback(char* topic, byte* message, unsigned int length);
void parseGuioMsg(const String &amp;msg);

std::string tiData{""}, niData{"1"};
char buf[100];

void setup() {
  // debug output
  Serial.begin(115200);
  
  // connect WiFi (keep trying...)
  Serial.print("Connecting to ");
  Serial.println(ssid);
  
  WiFi.begin(ssid, pass);
  while(WiFi.status() != WL_CONNECTED) { 
    Serial.print(".");
    delay(500); 
  }
  
  Serial.println("WiFi connected!"); 
  
  // setup mqtt
  mqttClient.setServer(mqttServer, 1883);
  mqttClient.setCallback(mqttCallback);
}

void loop() {
  while(!mqttClient.connected()) {
    Serial.println("MQTT connecting...");

    // mqtt client id is the mac address (AABBCCDDEEFF)
    char mqttClientId[15];    
    uint8_t mac[6];
    WiFi.macAddress(mac);

    snprintf(mqttClientId, sizeof(mqttClientId), "%02x%02x%02x%02x%02x%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);

    if(mqttClient.connect(mqttClientId, mqttUser, mqttPass)) {
      Serial.println("MQTT connected!");
      mqttClient.subscribe(&amp;Out[0]);
    }
    else {
      Serial.print("MQTT connection failed (");
      Serial.print(mqttClient.state());
      Serial.println(")! Retrying...");      
      delay(2500);
    }
  }
  mqttClient.loop();
}

// mqtt callback function
void mqttCallback(char* topic, byte* message, unsigned int length) {
  // build message string
  String msg;
  for(int i = 0; i &lt; length; i++) {
    msg += (char) message[i];
  }
  // parse message string
  parseGuioMsg(msg);
}

void parseGuioMsg(const String &amp;msg) {
  DEBUG("parseGuioMsg: ", msg);
  
  if(msg.startsWith("@init")) {
    Serial.println("GUI-O app is requesting INITIALIZATION!");

    // clear screen and set background
    mqttClient.publish(&amp;In[0], "@cls\r\n");
    mqttClient.publish(&amp;In[0], "@guis BGC:#FFFFFF\r\n");
    delay(100);

    // initialize GUI
    mqttClient.publish(&amp;In[0], "|LB UID:title X:50 Y:20 FSZ:4 FFA:\"font8\" TXT:\"Saving data\"\r\n");
    mqttClient.publish(&amp;In[0], "|BT UID:bt_save X:72.5 Y:30 BGC:#FDFDFD SBGC:#DCDFDF LOR:1 SHE:1 FSZ:2 TXT:\"Save\" BTH:0\r\n");
    mqttClient.publish(&amp;In[0], "|TI UID:ti_data X:30 Y:30 BGC:#004C4C4C FSZ:2\r\n");
    mqttClient.publish(&amp;In[0], "|BT UID:bt_all X:72.5 Y:38 BGC:#FDFDFD SBGC:#DCDFDF LOR:1 SHE:1 FSZ:2 TXT:\"Read all\" BTH:0\r\n");
    mqttClient.publish(&amp;In[0], "|BT UID:bt_line X:72.5 Y:46 BGC:#FDFDFD SBGC:#DCDFDF LOR:1 SHE:1 FSZ:2 TXT:\"Read line\" BTH:0\r\n");
    mqttClient.publish(&amp;In[0], "|NI UID:ni_data X:30 Y:46 W:30 BGC:#004C4C4C VAL:1 FSZ:2.5\r\n");
    mqttClient.publish(&amp;In[0], "|BT UID:clear_display X:92 Y:70 W:8 H:30 BGC:#FDFDFD SBGC:#DCDFDF LOR:1 SHE:1 FSZ:2 TXT:\"C&lt;br&gt;L&lt;br&gt;E&lt;br&gt;A&lt;br&gt;R\" BTH:0\r\n");
    mqttClient.publish(&amp;In[0], "|TA UID:display X:50 Y:70 W:70 BGC:#DCDFDF FSZ:2\r\n");
    mqttClient.publish(&amp;In[0], "|LB UID:details X:50 Y:90 FSZ:2 TXT:\"GUI-O data saving&lt;br&gt;demonstration by kl3m3n\"\r\n");
    // initialize "file saver"
    mqttClient.publish(&amp;In[0], "|EXTF UID:file HID:extf FNA:\"test.txt\" FAC:0\r\n");
  }
  else if(msg.startsWith("@bt_save")) {
    snprintf(buf, sizeof(buf), "@file FAC:1 FP:\"%s\"\r\n", tiData.c_str());
    mqttClient.publish(&amp;In[0], &amp;buf[0]);
    DEBUG("bt_save: ", tiData.c_str());
  }
  else if(msg.startsWith("@ti_data")) {
    auto input = std::string(msg.c_str());
    
    auto s_idx = input.find(' ');
    auto e_idx = input.find("dev:");  // NOTE: "dev" token exists only for IoT
    
    if(s_idx != std::string::npos
        &amp;&amp; e_idx != std::string::npos
        &amp;&amp; s_idx &lt; e_idx) {
          tiData = input.substr(s_idx + 1, e_idx - s_idx - 1);
          DEBUG("ti_data: ", tiData.c_str());
    }
  }
  else if(msg.startsWith("@bt_all")) {
    snprintf(buf, sizeof(buf), "@file FAC:2 FP:\"-1\"\r\n");
    mqttClient.publish(&amp;In[0], &amp;buf[0]);
    DEBUG("bt_all:", "");
  }
  else if(msg.startsWith("@bt_line")) {
    snprintf(buf, sizeof(buf), "@file FAC:2 FP:\"%s\"\r\n", niData.c_str());
    mqttClient.publish(&amp;In[0], &amp;buf[0]);
    DEBUG("bt_line: ", niData.c_str());
  }
  else if(msg.startsWith("@ni_data")) {
    auto input = std::string(msg.c_str());
    
    auto s_idx = input.find(' ');
    auto e_idx = input.find("dev:"); // NOTE: "dev" token exists only for IoT
    
    if(s_idx != std::string::npos
        &amp;&amp; e_idx != std::string::npos
        &amp;&amp; s_idx &lt; e_idx) {
          niData = input.substr(s_idx + 1, e_idx - s_idx - 1);
          DEBUG("ni_data: ", niData.c_str());
    }
  }
  else if(msg.startsWith("@file")) {
    auto input = std::string(msg.c_str());
    
    auto s_idx = input.find(' ');
    auto e_idx = input.find("dev:"); // NOTE: "dev" token exists only for IoT
    
    if(s_idx != std::string::npos
        &amp;&amp; e_idx != std::string::npos
        &amp;&amp; s_idx &lt; e_idx) {
          auto line = input.substr(s_idx + 1, e_idx - s_idx - 1);
          snprintf(buf, sizeof(buf), "@display TXT:\"%s\"\r\n", line.c_str());
          mqttClient.publish(&amp;In[0], &amp;buf[0]);
          DEBUG("@file: ", line.c_str());
    }    
  }
  else if(msg.startsWith("@clear_display")) {
    mqttClient.publish(&amp;In[0], "@display CL:1\r\n");
    DEBUG("@clear_display: ", "");
  }
}
</code></pre>
<h3>3. ESTABLISH CONNECTION</h3>
<p dir="auto">Make sure that the GUI-O application is connected to the MQTT server.<br />
Also make sure that the ESP32 board (or other Arduino supported board) is connected to the MQTT server (you can check this by observing the serial debug messages using the Arduino serial monitor).</p>
<p dir="auto">Press the <strong>Initialize</strong> button (see image below) from the GUI-O application home screen.</p>
<p dir="auto"><img src="https://i.imgur.com/DDEHAR7l.jpg" alt="initialize_button.jpg" class=" img-fluid img-markdown" /></p>
<h3>4. THE RESULT</h3>
<p dir="auto">Images (and video) below show the result (screen capture) on my Android device after pressing the "Initialize" button, saving some data and reading it back. All actions are triggered through GUI interaction.</p>
<p dir="auto"><img src="https://i.imgur.com/ayglPZAl.jpg" alt="save_load.jpg" class=" img-fluid img-markdown" /></p>
<p dir="auto"></p><div class="video-embed"><iframe allowfullscreen src="//www.youtube.com/embed/T-uzrWLklzY"></iframe></div><p></p>
<hr />
<p dir="auto">If you have any questions or run into any problems, please let me know!</p>
<p dir="auto">Best regards,<br />
kl3m3n</p>
]]></description><link>https://forum.gui-o.com/topic/124/episode-14-saving-data-to-android-device</link><guid isPermaLink="true">https://forum.gui-o.com/topic/124/episode-14-saving-data-to-android-device</guid><dc:creator><![CDATA[kl3m3n]]></dc:creator><pubDate>Sat, 11 Mar 2023 18:58:31 GMT</pubDate></item><item><title><![CDATA[Episode 13: Drawing charts]]></title><description><![CDATA[<p dir="auto">This episode shows the different chart types that are supported by GUI-O application:</p>
<ol>
<li><strong>Time chart</strong></li>
<li><strong>XY chart</strong></li>
<li><strong>Sweep chart</strong></li>
</ol>
<p dir="auto">All charts are highly customizable.</p>
<p dir="auto"><strong>I will be using GUI-O IoT (MQTT) connection, but the example can be easily be ported to other connection types.</strong></p>
<p dir="auto"><strong>Software prerequisites:</strong></p>
<ul>
<li>
<p dir="auto">Arduino IDE (<a href="https://www.arduino.cc/en/software" rel="nofollow ugc">https://www.arduino.cc/en/software</a>)</p>
</li>
<li>
<p dir="auto">ESP32 Arduino board support, if using ESP32 based board (see <a href="https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html" rel="nofollow ugc">https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html</a>)</p>
</li>
<li>
<p dir="auto">Arduino Client for MQTT(<a href="https://github.com/knolleary/pubsubclient" rel="nofollow ugc">https://github.com/knolleary/pubsubclient</a>)<br />
You can follow the setup instructions or directly download and include the <strong><a href="https://drive.google.com/uc?export=download&amp;id=1yRJCDFR2xQDodyIA_lqKfcYdU6pAFy1C" rel="nofollow ugc">PubSubClient.zip</a></strong> library within the Arduino IDE (Sketch -&gt; Include Library -&gt; Add .ZIP library)</p>
</li>
<li>
<p dir="auto">GUI-O design tool (<a href="https://www.gui-o.com/design-tool" rel="nofollow ugc">https://www.gui-o.com/design-tool</a>)</p>
</li>
<li>
<p dir="auto">GUI-O application (<a href="https://play.google.com/store/apps/details?id=com.guio.guioapp" rel="nofollow ugc">https://play.google.com/store/apps/details?id=com.guio.guioapp</a>)</p>
</li>
<li>
<p dir="auto">For additional information about the GUI-O application, download the developer manual from <a href="https://www.gui-o.com/" rel="nofollow ugc">https://www.gui-o.com/</a></p>
</li>
</ul>
<p dir="auto"><strong>Components needed:</strong></p>
<ul>
<li>ESP32-WROOM-32 (or any other Arduino supported WiFi capable board; see <a href="https://github.com/knolleary/pubsubclient#compatible-hardware" rel="nofollow ugc">https://github.com/knolleary/pubsubclient#compatible-hardware</a> for compatible hardware)</li>
</ul>
<p dir="auto"><strong>The entire tutorial is split into various steps. All necessary information is given in each step</strong>.</p>
<h3>0. DESIGN THE GUI (optional)</h3>
<p dir="auto">The best way to create a GUI layout is to use GUI-O live designer tool.</p>
<p dir="auto">Note that the Arduino source code already includes the necessary commands, so this step is not needed, unless you want to make some visual adjustments. If you make adjustments, please include the generated ASCII code in the Arduino source code (see section 2. MODIFY AND UPLOAD THE SOURCE CODE).</p>
<p dir="auto">First, you need to establish a TCP/IP connection between the designer tool and GUI-O application:</p>
<ol>
<li>Determine the local IP address of your PC's network interface (WiFi or Ethernet)</li>
</ol>
<ul>
<li>Under Windows, open the command prompt, enter <code>ipconfig</code> and press Enter</li>
<li>Under Linux, open the terminal, enter <code>ifconfig</code> and press Enter</li>
</ul>
<ol start="2">
<li>
<p dir="auto">Open GUI-O application and open settings menu. Select "Connections -&gt; Ethernet" and create a new device with IP address (determined from 1.) and any port between 49152 - 65535</p>
</li>
<li>
<p dir="auto">Open GUI-O designer and select "TCP/IP connection" tab. Set the IP address and port. Both values must match the device settings created within the GUI-O application. Click "Start server" button.</p>
</li>
<li>
<p dir="auto">Within the GUI-O application, tap the created device and wait for successful connection.</p>
</li>
<li>
<p dir="auto">In the GUI-O designer, select "File -&gt; Load designer file" and load the <a href="https://drive.google.com/uc?export=download&amp;id=1NJnFUAjeUD-DhWe9MdUVR5ClTxwF6Qno" rel="nofollow ugc">ChartDrawing.gdf</a> design file. Make the desired adjustments, if necessary. Copy / replace the GUI-O commands into the Arduino source code (see section 3. MODIFY AND UPLOAD THE SOURCE CODE).</p>
</li>
</ol>
<h3>1. CREATE A UNIQUE MQTT CHANNEL</h3>
<p dir="auto">Open GUI-O application and press <strong>Add</strong> from home screen (top-right corner of the display). Select "IoT (Create device)" and add a new device. After adding the device, note the <strong>In</strong> and <strong>Out</strong> token (you can share this tokens e.g., to your e-mail by pressing the "share" button).</p>
<p dir="auto">Finally, press "Connect" menu entry to establish the connection with the MQTT server.</p>
<h3>2. MODIFY AND UPLOAD THE SOURCE CODE</h3>
<p dir="auto">The source code has inline comments, describing the important parts of the code. You can copy the source code from the snippet below, or download it <a href="https://drive.google.com/uc?export=download&amp;id=1UiQ_8gOAAYS3W2S7V4JOo2wKj0Wm22DB" rel="nofollow ugc">here</a>.</p>
<p dir="auto">The only thing that needs to be done is to set the <strong>ssid</strong> and <strong>password</strong> of your router and the unique <strong>In</strong> and <strong>Out</strong> channels that were generated by the GUI-O application (see section 1. CREATE A UNIQUE MQTT CHANNEL).</p>
<p dir="auto">After setting these values, upload the code to your board (make sure that the correct board and upload port are selected). Reset the board after upload.</p>
<pre><code>/*
 * GUI-O Chart Drawing MQTT example (using ESP32-WROOM-32)
 *
 * Copyright (C) 2023, kl3m3n
 * last updated on 5.3.2023
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include &lt;WiFi.h&gt;
#include &lt;PubSubClient.h&gt;

static const char *ssid = "&lt;ssid&gt;"; // router name
static const char *pass = "&lt;pass&gt;"; // router password

static const char *mqttServer = "mqtt.gui-o.com";   // host name
static const char *mqttUser = "gui-o-mqtt-generic"; // user name
static const char *mqttPass = "lqXeZpv5VJyv0XBT";   // password

// IMPORTANT NOTE: if optional user name was specified when adding a new IoT device,
// the user name should also be included when setting the topics (e.g., "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/&lt;user_name&gt;")
static const char *Out = "&lt;Out&gt;"; // GUI-O app publish topic
static const char *In = "&lt;In&gt;";  // GUI-O app subscribe topic

// mqtt client
WiFiClient wiFiClient;
PubSubClient mqttClient(wiFiClient);

// forward declare functions for mqtt messages handling
void mqttCallback(char* topic, byte* message, unsigned int length);
void parseGuioMsg(const String &amp;msg);

// setup chart settings / options
enum class ChartType {
  TimeChart = 0,
  XYChart,
  SweepChart,
  Invalid = -1  
};
ChartType chartType = ChartType::Invalid;
static long int counter = 0;
char buf[100];
unsigned long startTimestampMsec, currentTimestampMsec;
const unsigned long updateIntervalMsec = 150; // milliseconds

void setup() {
  // debug output
  Serial.begin(115200);
  
  // connect WiFi (keep trying...)
  Serial.print("Connecting to ");
  Serial.println(ssid);
  
  WiFi.begin(ssid, pass);
  while(WiFi.status() != WL_CONNECTED) { 
    Serial.print(".");
    delay(500); 
  }
  
  Serial.println("WiFi connected!"); 
  
  // setup mqtt
  mqttClient.setServer(mqttServer, 1883);
  mqttClient.setCallback(mqttCallback);

  startTimestampMsec = millis();
}

void loop() {
  while(!mqttClient.connected()) {
    Serial.println("MQTT connecting...");

    // mqtt client id is the mac address (AABBCCDDEEFF)
    char mqttClientId[15];    
    uint8_t mac[6];
    WiFi.macAddress(mac);

    snprintf(mqttClientId, sizeof(mqttClientId), "%02x%02x%02x%02x%02x%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);

    if(mqttClient.connect(mqttClientId, mqttUser, mqttPass)) {
      Serial.println("MQTT connected!");
      mqttClient.subscribe(&amp;Out[0]);
    }
    else {
      Serial.print("MQTT connection failed (");
      Serial.print(mqttClient.state());
      Serial.println(")! Retrying...");      
      delay(2500);
    }
  }
  mqttClient.loop();

  // update chart?
  currentTimestampMsec = millis();
  if(currentTimestampMsec - startTimestampMsec &gt; updateIntervalMsec) {
    switch(chartType) {
      case ChartType::TimeChart:
      {
        double yValue = 5 * sin(2 * M_PI * counter++ * 0.015);
        snprintf(buf, sizeof(buf), "@chart PLI:\"id0\" PLC:\"#D89D3B\" YP:\"%.1f\"\r\n", yValue);
        mqttClient.publish(&amp;In[0], &amp;buf[0]);
        break;
      }
      case ChartType::XYChart:
      {
        long int xValue = counter;
        double yValue = 5 * sin(2 * M_PI * counter++ * 0.015);
        snprintf(buf, sizeof(buf), "@chart PLI:\"id0\" PLC:\"#05B6EA\" XP:\"%d\" YP:\"%.1f\"\r\n", xValue, yValue);
        mqttClient.publish(&amp;In[0], &amp;buf[0]);
        break;
      }
      case ChartType::SweepChart:
      {
        double yValue = 5 * sin(2 * M_PI * counter++ * 0.015);
        snprintf(buf, sizeof(buf), "@chart PLI:\"id0\" PLC:\"#AE3C51\" YP:\"%.1f\"\r\n", yValue);
        mqttClient.publish(&amp;In[0], &amp;buf[0]);
        break;
      }
      case ChartType::Invalid:
        default:
        break;
    }
    // reset read interval
    startTimestampMsec = millis();
  }
}

// mqtt callback function
void mqttCallback(char* topic, byte* message, unsigned int length) {
  // build message string
  String msg;
  for(int i = 0; i &lt; length; i++) {
    msg += (char) message[i];
  }
  // parse message string
  parseGuioMsg(msg);
}

void parseGuioMsg(const String &amp;msg) {
  if(msg.startsWith("@init")) {
    Serial.println("GUI-O app is requesting INITIALIZATION!");

    // clear screen and set background
    mqttClient.publish(&amp;In[0], "@cls\r\n");
    mqttClient.publish(&amp;In[0], "@guis BGC:#FFFFFF\r\n");
    delay(100);

    // initialize GUI (setup time chart by default)
    mqttClient.publish(&amp;In[0], "|LB UID:title X:50 Y:20 FSZ:4 FFA:\"font8\" TXT:\"Chart drawing\"\r\n");
    mqttClient.publish(&amp;In[0], "|CH UID:chart X:50 Y:50 W:90 H:30 BGC:#4C4C4C FGC:#D89D3B FSZ:1.5 BTH:0 CHN:\"Value vs Time\" AT:0.2 XTC:1 XMA:8 YMA:4 YLO:-10 SHG:0 SHXA:0 SHYA:0\r\n");
    mqttClient.publish(&amp;In[0], "|BT UID:timebt X:20 Y:70 FGC:#D89D3B BTH:0 SHE:1 TXT:\"Time\"\r\n");
    mqttClient.publish(&amp;In[0], "|BT UID:xybt X:50 Y:70 FGC:#D89D3B BTH:0 SHE:1 TXT:\"XY\"\r\n");
    mqttClient.publish(&amp;In[0], "|BT UID:sweepbt X:80 Y:70 FGC:#D89D3B BTH:0 SHE:1 TXT:\"Sweep\"\r\n");
    mqttClient.publish(&amp;In[0], "|LB UID:details X:50 Y:90 FSZ:2 TXT:\"GUI-O charts demonstration by kl3m3n\"\r\n");
  }
  // time chart mode
  else if(msg.startsWith("@timebt")) {
    // clear and initialize chart
    mqttClient.publish(&amp;In[0], "@cls UIDS:\"chart\"");
    mqttClient.publish(&amp;In[0], "|CH UID:chart X:50 Y:50 W:90 H:30 BGC:#4C4C4C FGC:#D89D3B FSZ:1.5 BTH:0 CHN:\"Value vs Time\" AT:0.2 XTC:1 XMA:8 YMA:4 YLO:-10 SHG:0 SHXA:0 SHYA:0\r\n");
    chartType = ChartType::TimeChart;
    counter = 0;
  }
  // xy chart mode
  else if(msg.startsWith("@xybt")) {
    // clear and initialize chart
    mqttClient.publish(&amp;In[0], "@cls UIDS:\"chart\"");
    mqttClient.publish(&amp;In[0], "|CH UID:chart X:50 Y:50 W:90 H:30 BGC:#4C4C4C FGC:#D89D3B FSZ:1.5 BTH:0 CHT:1 CHN:\"X Value vs Y Value\" AT:0.2 YLO:-10 XTC:10 YTC:10 XMA:8 YMA:5\r\n");
    chartType = ChartType::XYChart;
    counter = 0;
  }
  // sweep chart
  else if(msg.startsWith("@sweepbt")) {
    // clear and initialize chart
    mqttClient.publish(&amp;In[0], "@cls UIDS:\"chart\"");
    mqttClient.publish(&amp;In[0], "|CH UID:chart X:50 Y:50 W:90 H:30 BGC:#4C4C4C FGC:#D89D3B FSZ:1.5 BTH:0 CHT:2 BSZ:256 CHN:\"Sweep\" AT:0.2 YLO:-10 XTC:4 YTC:4 XMA:8 YMA:4 XHI:100 DRA:0 SHG:0 SHXA:0 SHYA:0 SHSL:1 SHVL:0\r\n");
    chartType = ChartType::SweepChart;
    counter = 0;
  }
}
</code></pre>
<h3>3. ESTABLISH CONNECTION</h3>
<p dir="auto">Make sure that the GUI-O application is connected to the MQTT server.<br />
Also make sure that the ESP32 board (or other Arduino supported board) is connected to the MQTT server (you can check this by observing the serial debug messages using the Arduino serial monitor).</p>
<p dir="auto">Press the <strong>Initialize</strong> button (see image below) from the GUI-O application home screen.</p>
<p dir="auto"><img src="https://i.imgur.com/DDEHAR7l.jpg" alt="initialize_button.jpg" class=" img-fluid img-markdown" /></p>
<h3>4. THE RESULT</h3>
<p dir="auto">Images (and video) below show the result (screen capture) on my Android device after pressing the "Initialize" button and selecting <strong>Time</strong>, <strong>XY</strong> and <strong>Sweep</strong>, respectively. The active chart is updated every time the ESP32 board published new data to the MQTT server.</p>
<p dir="auto"><img src="https://i.imgur.com/MU5i5Tnl.jpg" alt="time.jpg" class=" img-fluid img-markdown" /><br />
<img src="https://i.imgur.com/LUhUvqyl.jpg" alt="xy.jpg" class=" img-fluid img-markdown" /><br />
<img src="https://i.imgur.com/oLBTzh6l.jpg" alt="sweeps.jpg" class=" img-fluid img-markdown" /></p>
<p dir="auto"></p><div class="video-embed"><iframe allowfullscreen src="//www.youtube.com/embed/cBz22J5tKno"></iframe></div><p></p>
<hr />
<p dir="auto">If you have any questions or run into any problems, please let me know!</p>
<p dir="auto">Best regards,<br />
kl3m3n</p>
]]></description><link>https://forum.gui-o.com/topic/122/episode-13-drawing-charts</link><guid isPermaLink="true">https://forum.gui-o.com/topic/122/episode-13-drawing-charts</guid><dc:creator><![CDATA[kl3m3n]]></dc:creator><pubDate>Sun, 05 Mar 2023 12:40:38 GMT</pubDate></item><item><title><![CDATA[Episode 12: Adding and connecting new device from GUI-O home screen]]></title><description><![CDATA[<h1>EPISODE 12: Adding and connecting new device from GUI-O home screen</h1>
<p dir="auto">This tutorial shows how to <strong>add</strong> and <strong>connect</strong> devices directly from GUI-O home screen. <strong>GUI-O supports various connection types and various methods to add devices.</strong></p>
<p dir="auto">This tutorial shows how to connect ESP32 working in Bluetooth LE (Low Energy) mode with Nordic UART Service (NUS).</p>
<ol>
<li>
<p dir="auto">Download <a href="https://drive.google.com/uc?export=download&amp;id=1OVhITiGA2CAfbz2kE0QTNLCD5d2YBUAu" rel="nofollow ugc">BasicBLE_NUS.ino</a> sketch.</p>
</li>
<li>
<p dir="auto">Follow Basic BLE video tutorial below to setup ESP32 (<strong>NOTE: stop video after the sketch is uploaded to ESP32 and refer to the video under step 3. below</strong>).</p>
</li>
</ol>
<p dir="auto">Additional Boards Manager URLs: <a href="https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json" rel="nofollow ugc">https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json</a></p>
<p dir="auto"></p><div class="video-embed"><iframe allowfullscreen src="//www.youtube.com/embed/DgyfXlsWdwc"></iframe></div><p></p>
<ol start="3">
<li>Check the video below to <strong>add</strong> and <strong>connect</strong> the Bluetooth LE device.</li>
</ol>
<p dir="auto"></p><div class="video-embed"><iframe allowfullscreen src="//www.youtube.com/embed/LVUzhcpK6uY"></iframe></div><p></p>
<hr />
<p dir="auto">If you have any questions or run into any problems, please let me know!</p>
<p dir="auto">Best regards,<br />
kl3m3n</p>
]]></description><link>https://forum.gui-o.com/topic/101/episode-12-adding-and-connecting-new-device-from-gui-o-home-screen</link><guid isPermaLink="true">https://forum.gui-o.com/topic/101/episode-12-adding-and-connecting-new-device-from-gui-o-home-screen</guid><dc:creator><![CDATA[kl3m3n]]></dc:creator><pubDate>Mon, 30 Jan 2023 17:40:05 GMT</pubDate></item><item><title><![CDATA[Episode 11: Pairing GUI-O with ESP32 (MQTT mode)]]></title><description><![CDATA[<p dir="auto"><strong>NOTE</strong>: The following tutorial applies to IoT (MQTT) connection mode only.</p>
<p dir="auto">This tutorial will show how to easily pair ESP32 with GUI-O application in IoT (MQTT) connection mode. The pairing procedure is automated (guided) and requires only necessary user input (e.g., selecting WiFi router and inputting router password). You can even implement the pairing protocol yourself on your specific device (visit <a href="http://www.gui-o.com" rel="nofollow ugc">www.gui-o.com</a> and download the developer manual for more information).</p>
<p dir="auto">To see the ESP8266 pairing example (and other examples), navigate to <a href="https://www.gui-o.com/examples" rel="nofollow ugc">https://www.gui-o.com/examples</a>.</p>
<p dir="auto"><strong>Prerequisites:</strong></p>
<ul>
<li>
<p dir="auto">ESP32 based board</p>
</li>
<li>
<p dir="auto">Download <a href="https://www.arduino.cc/en/software" rel="nofollow ugc">Arduino IDE</a></p>
</li>
<li>
<p dir="auto">Download <a href="https://drive.google.com/uc?export=download&amp;id=1Ooo7mslmrZsaqfbwQMtdXznkWsPNVxdb" rel="nofollow ugc">ESP32_GUI-O_pairing_libs.zip</a> and extract the archive (the archive contains a bundle of necessary libraries, you can alternatively install them yourself using the "Arduino library manager")</p>
</li>
<li>
<p dir="auto">Download <a href="https://drive.google.com/uc?export=download&amp;id=1PJ90pegULFj_SkC-6BOgpSoO2cL_8NYm" rel="nofollow ugc">ESP32_GUI-O_pairing_source.zip</a> or <a href="https://drive.google.com/uc?export=download&amp;id=1vP0lEjzOv6dCapoShwogn0kr66oeJw4M" rel="nofollow ugc">ESP32_GUI-O_pairing_source_SSL_TLS.zip</a> (for secure connection) and extract the archive</p>
</li>
</ul>
<h3>Add ESP32 board support</h3>
<ol>
<li>
<p dir="auto">Open Arduino IDE</p>
</li>
<li>
<p dir="auto">Select "File -&gt; Preferences" and under Additional Boards Manager URLs enter: <a href="https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json" rel="nofollow ugc">https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json</a></p>
</li>
<li>
<p dir="auto">Select "Tools -&gt; Board -&gt; Boards manager..."</p>
</li>
<li>
<p dir="auto">Search and install "esp32" by Espressif Systems</p>
</li>
<li>
<p dir="auto">After installation select "Tools -&gt; Board -&gt; ESP32 Arduino -&gt; ESP32 Dev Module"</p>
</li>
</ol>
<h3>Include necessary libraries</h3>
<ol>
<li>
<p dir="auto">Select "Sketch -&gt; Include library -&gt; Add .ZIP library..."</p>
</li>
<li>
<p dir="auto">Navigate to location, where ESP32_GUI-O_pairing_libs.zip archive was extracted</p>
</li>
<li>
<p dir="auto">Select .zip library and confirm (repeat procedure until all .zip libraries are included)</p>
</li>
</ol>
<h3>Upload the code</h3>
<ol>
<li>
<p dir="auto">Select "File -&gt; Open"</p>
</li>
<li>
<p dir="auto">Navigate to location, where ESP32_GUI-O_pairing_source.zip archive was extracted</p>
</li>
<li>
<p dir="auto">Select PairingMQTT.ino and confirm</p>
</li>
<li>
<p dir="auto">Make sure that ESP32 board is connected to your PC</p>
</li>
<li>
<p dir="auto">Make sure that the correct port is selected</p>
</li>
<li>
<p dir="auto">Press upload button to start code upload (IMPORTANT NOTE: on some ESP32 boards, the BOOT button must be pressed when the upload starts)</p>
</li>
<li>
<p dir="auto">Reset ESP32 board after code upload</p>
</li>
</ol>
<p dir="auto">The video tutorial below shows the above steps.</p>
<p dir="auto"></p><div class="video-embed"><iframe allowfullscreen src="//www.youtube.com/embed/ewn9atxzD0E"></iframe></div><p></p>
<h3>Pair GUI-O application with ESP32 board</h3>
<p dir="auto">The pairing procedure is fully guided within GUI-O application. The important parts are described below.</p>
<ol>
<li>
<p dir="auto">Open GUI-O application and navigate to settings</p>
</li>
<li>
<p dir="auto">Make sure that IoT connection is active (select "Connections -&gt; IoT")</p>
</li>
<li>
<p dir="auto">From main settings menu select "Quick pair -&gt; Direct device pairing"</p>
</li>
<li>
<p dir="auto">Name your ESP32 device (setting your user name is optional) and confirm</p>
</li>
<li>
<p dir="auto">Wait while surrounding WiFi networks are scanned then select your (router) WiFi network and input your password</p>
</li>
<li>
<p dir="auto">Put the ESP32 device into pairing mode then search and connect to guio_ device (input password 12345678 when prompted)</p>
</li>
<li>
<p dir="auto">IMPORTANT NOTE: Do not switch network if prompted by Android (keep connection to guio_ device)</p>
</li>
<li>
<p dir="auto">Press "back button" and wait for pairing procedure to complete successfully</p>
</li>
<li>
<p dir="auto">Select your (router) WiFi network and press "back button" to start the connection test</p>
</li>
</ol>
<p dir="auto">The video tutorial below shows the above steps.</p>
<p dir="auto"></p><div class="video-embed"><iframe allowfullscreen src="//www.youtube.com/embed/CwDhKC2y-T8"></iframe></div><p></p>
<hr />
<p dir="auto">If you have any questions or run into any problems, please let me know!</p>
<p dir="auto">Best regards,<br />
kl3m3n</p>
]]></description><link>https://forum.gui-o.com/topic/98/episode-11-pairing-gui-o-with-esp32-mqtt-mode</link><guid isPermaLink="true">https://forum.gui-o.com/topic/98/episode-11-pairing-gui-o-with-esp32-mqtt-mode</guid><dc:creator><![CDATA[kl3m3n]]></dc:creator><pubDate>Sun, 01 Jan 2023 17:26:10 GMT</pubDate></item><item><title><![CDATA[Episode 10: Migrating to HiveMQ broker]]></title><description><![CDATA[<p dir="auto"><strong>NOTE</strong>: The following tutorial applies to IoT (MQTT) connection mode only.</p>
<p dir="auto">By default, GUI-O application uses a MQTT test broker that is running on our own server. The broker listens on ports 1883 (unencrypted), 8883 (encrypted with client certificates) and 8884 (encrypted). This is perfect for testing and some smaller use cases, but some IoT scenarios require using a broker platform that gives you finer control over additional settings (e.g., managing credentials for different clients).</p>
<p dir="auto">There are numerous platforms that offer managed cloud MQTT broker, such as HiveMQ, EMQX, CloudMQTT, etc. This episode focuses on migrating from GUI-O broker to HiveMQ broker using ESP32 board.</p>
<p dir="auto"><strong>Software prerequisites:</strong></p>
<ul>
<li>
<p dir="auto">Arduino IDE (<a href="https://www.arduino.cc/en/software" rel="nofollow ugc">https://www.arduino.cc/en/software</a>)</p>
</li>
<li>
<p dir="auto">ESP32 Arduino board support (see <a href="https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html" rel="nofollow ugc">https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html</a>)</p>
</li>
<li>
<p dir="auto">Arduino Client for MQTT(<a href="https://github.com/knolleary/pubsubclient" rel="nofollow ugc">https://github.com/knolleary/pubsubclient</a>)<br />
You can follow the setup instructions or directly download and include the <strong><a href="https://drive.google.com/uc?export=download&amp;id=1yRJCDFR2xQDodyIA_lqKfcYdU6pAFy1C" rel="nofollow ugc">PubSubClient.zip</a></strong> library within the Arduino IDE (Sketch -&gt; Include Library -&gt; Add .ZIP library)</p>
</li>
<li>
<p dir="auto">GUI-O application (<a href="https://play.google.com/store/apps/details?id=com.guio.guioapp" rel="nofollow ugc">https://play.google.com/store/apps/details?id=com.guio.guioapp</a>)</p>
</li>
</ul>
<p dir="auto"><strong>Components needed:</strong></p>
<ul>
<li>ESP32-WROOM-32 (or any other Arduino supported WiFi capable board; see <a href="https://github.com/knolleary/pubsubclient#compatible-hardware" rel="nofollow ugc">https://github.com/knolleary/pubsubclient#compatible-hardware</a> for compatible hardware)</li>
</ul>
<p dir="auto"><strong>The entire tutorial is split into various steps. All necessary information is given in each step</strong>.</p>
<h3>1. SETUP HIVEMQ</h3>
<ol>
<li>
<p dir="auto">Navigate to <a href="https://www.hivemq.com/downloads/" rel="nofollow ugc">https://www.hivemq.com/downloads/</a> and signup to (free) HiveMQ cloud plan</p>
</li>
<li>
<p dir="auto">Login to HiveMQ cloud console and navigate to "Clusters"</p>
</li>
<li>
<p dir="auto">Create a new cluster selecting any cloud service provider</p>
</li>
<li>
<p dir="auto">Select "MANAGE CLUSTER" (NOTE: The "Cluster URL" is required later)</p>
</li>
<li>
<p dir="auto">Select "ACCESS MANAGEMENT" tab and add new credentials (at least one)</p>
</li>
</ol>
<p dir="auto">All steps are shown in the video below.</p>
<p dir="auto"></p><div class="video-embed"><iframe allowfullscreen src="//www.youtube.com/embed/lF21bb3GcSg"></iframe></div><p></p>
<h3>2. SETUP GUI-O FOR HIVEMQ</h3>
<ol>
<li>
<p dir="auto">Open GUI-O application, open settings and navigate to "Connections -&gt; IoT -&gt; IoT Settings"</p>
</li>
<li>
<p dir="auto">Set the "Server name" using the HiveMQ "Cluster URL" (see 1. SETUP HIVEMQ).</p>
</li>
<li>
<p dir="auto">Set the "SSL port number" to 8883</p>
</li>
<li>
<p dir="auto">Set the "User name" and "User password" based on the HiveMQ credentials (see 1. SETUP HIVEMQ)</p>
</li>
<li>
<p dir="auto">Navigate to "Connections -&gt; IoT" and press "Connect" to test the connection</p>
</li>
</ol>
<p dir="auto">All steps are shown in the video below.</p>
<p dir="auto"></p><div class="video-embed"><iframe allowfullscreen src="//www.youtube.com/embed/gy7jAbex3FQ"></iframe></div><p></p>
<h3>3. SETUP ESP32 FOR HIVEMQ</h3>
<ol>
<li>
<p dir="auto">Download <a href="https://drive.google.com/uc?export=download&amp;id=13eGCiI8tlx_EMHODwBjUvnQ5MxINc5Iv" rel="nofollow ugc">BasicMQTT_HiveMQ.ino</a> sketch and open it in Arduino IDE</p>
</li>
<li>
<p dir="auto">Get the certificate of your HiveMQ broker (see video below)</p>
<ul>
<li>On Linux, open the terminal and enter command:</li>
</ul>
<blockquote>
<p dir="auto">openssl s_client -connect &lt;hivemq_url&gt;:8883 -showcerts</p>
</blockquote>
<p dir="auto">replacing the &lt;hivemq_url&gt; with the "Cluster URL" (see 1. SETUP HIVEMQ)</p>
<ul>
<li>
<p dir="auto">You can alternatively use an online Linux terminal (e.g., <a href="https://www.tutorialspoint.com/linux_terminal_online.php" rel="nofollow ugc">https://www.tutorialspoint.com/linux_terminal_online.php</a>) to execute the same command</p>
</li>
<li>
<p dir="auto">After running the command, copy the last certificate displayed in the terminal and replace the one in the downloaded Arduino sketch (keep same certificate formatting)</p>
</li>
</ul>
<p dir="auto"></p><div class="video-embed"><iframe allowfullscreen src="//www.youtube.com/embed/XxxOeyom_6c"></iframe></div><p></p>
</li>
<li>
<p dir="auto">Use the downloaded Arduino sketch (i.e.,  <strong>BasicMQTT_HiveMQ.ino</strong>) while referring to the video below. Make sure that the <strong>server url</strong>, <strong>user name</strong> and <strong>password</strong> are set <strong>according to HIVEMQ setup</strong> (see  1. SETUP HIVEMQ)</p>
<p dir="auto"></p><div class="video-embed"><iframe allowfullscreen src="//www.youtube.com/embed/yuswQMyzg6A"></iframe></div><p></p>
</li>
</ol>
<hr />
<p dir="auto">If you have any questions or run into any problems, please let me know!</p>
<p dir="auto">Best regards,<br />
kl3m3n</p>
]]></description><link>https://forum.gui-o.com/topic/95/episode-10-migrating-to-hivemq-broker</link><guid isPermaLink="true">https://forum.gui-o.com/topic/95/episode-10-migrating-to-hivemq-broker</guid><dc:creator><![CDATA[kl3m3n]]></dc:creator><pubDate>Sun, 25 Dec 2022 17:41:15 GMT</pubDate></item><item><title><![CDATA[Episode 9: GUI-O and HM-10 BLE]]></title><description><![CDATA[<p dir="auto">The following example shows how to connect GUI-O app with HM-10 Bluetooth Low Energy (BLE) module. Arduino Uno is used as an intermediary between the HM-10 and PC serial terminal.</p>
<p dir="auto"><strong>Software prerequisites:</strong></p>
<ul>
<li>
<p dir="auto">Arduino IDE (<a href="https://www.arduino.cc/en/software" rel="nofollow ugc">https://www.arduino.cc/en/software</a>)</p>
</li>
<li>
<p dir="auto">GUI-O application (<a href="https://play.google.com/store/apps/details?id=com.guio.guioapp" rel="nofollow ugc">https://play.google.com/store/apps/details?id=com.guio.guioapp</a>), updated to at least <strong>v1.0.25</strong></p>
</li>
<li>
<p dir="auto">For additional information about the GUI-O application, download the developer manual from <a href="https://www.gui-o.com/" rel="nofollow ugc">https://www.gui-o.com/</a></p>
</li>
</ul>
<p dir="auto"><strong>Components needed:</strong></p>
<ul>
<li>HM-10 BLE module</li>
<li>Arduino Uno</li>
</ul>
<p dir="auto"><strong>The entire tutorial is split into various steps. All necessary information is given in each step</strong>.</p>
<h3>1. CONNECT THE COMPONENTS</h3>
<p dir="auto">Connect the components as shown in the schematic below. Note that the Arduino Uno transmit pin (pin "D3") uses a voltage divider to reduce 5V to roughly 3.3V.</p>
<p dir="auto"><img src="https://i.imgur.com/p7Ov5UVl.png" alt="schematic.png" class=" img-fluid img-markdown" /></p>
<h3>2. UPLOAD THE SOURCE CODE</h3>
<p dir="auto">The source code is really simple and has inline comments, describing the parts of the code. You can copy the source code from the snippet below, or download it <a href="https://drive.google.com/uc?export=download&amp;id=14V0jg_0fdsQqDcxg8kpotrFxjukQPTgE" rel="nofollow ugc">here</a>.</p>
<p dir="auto">Upload the code to your Arduino Uno board (make sure that the correct board and upload port are selected).</p>
<pre><code>/*
 * GUI-O BLE HM-10 example (using HM-10 and Arduino Uno)
 *
 * Copyright (C) 2022, GUI-O Team
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include &lt;SoftwareSerial.h&gt;

// communicating with HM-10 using Arduino Uno 
// via software serial, so set it up (Rx - pin2, Tx - pin3)
SoftwareSerial bt(2, 3);

void setup() {
  // 1. Arduino Uno sends data to HM-10 (via PC teriminal)
  // 2. Arduino Uno receives data from HM-10
  Serial.begin(115200);
  
  // 1. HM-10 sends data Arduino Uno
  // 2. HM-10 receives data from Arduino Uno
  bt.begin(9600);
}

void loop() {
  // listen for HM-10 data
  bt.listen();

  // if HM-10 has data, send it to Arduino Uno to be displayed on PC terminal
  while(bt.available() &gt; 0) {
    Serial.write(bt.read());
  }

  // if Arduino Uno has data (via PC terminal), send it to HM-10
  if(Serial.available()) {
    delay(10);
    bt.write(Serial.read());
  }
}
</code></pre>
<h3>3. ESTABLISH CONNECTION</h3>
<ol>
<li>
<p dir="auto">Open GUI-O app, navigate to settings and select "Connections -&gt; Bluetooth LE"</p>
</li>
<li>
<p dir="auto">Search for BLE devices (enable Bluetooth and Location services, if prompted)</p>
</li>
<li>
<p dir="auto">Select HM-10 module (named HMSoft or similar)</p>
</li>
<li>
<p dir="auto">Wait for successful connection</p>
</li>
<li>
<p dir="auto">Open any serial terminal on PC (e.g., Arduino Serial Monitor)</p>
</li>
<li>
<p dir="auto">Close the settings menu and press the <strong>Initialize</strong> button (see image below) from the GUI-O application home screen and observe the result on serial terminal on PC</p>
</li>
</ol>
<p dir="auto"><img src="https://i.imgur.com/DDEHAR7l.jpg" alt="initialize_button.jpg" class=" img-fluid img-markdown" /></p>
<ol start="7">
<li>Send any valid command (see example below) via serial terminal on PC and observe the result in GUI-O app</li>
</ol>
<p dir="auto"><strong>EXAMPLE COMMAND</strong>:  "<strong>|TG UID:toggle X:50 Y:50</strong>" (omitting the quotes). Make sure all commands are terminated by carriage return (<strong>\r</strong>) and line feed (<strong>\n</strong>). See the GUI-O manual for all supported commands.</p>
<hr />
<p dir="auto">If you have any questions or run into any problems, please let me know!</p>
<p dir="auto">Best regards,<br />
kl3m3n</p>
]]></description><link>https://forum.gui-o.com/topic/94/episode-9-gui-o-and-hm-10-ble</link><guid isPermaLink="true">https://forum.gui-o.com/topic/94/episode-9-gui-o-and-hm-10-ble</guid><dc:creator><![CDATA[kl3m3n]]></dc:creator><pubDate>Sun, 11 Dec 2022 17:58:03 GMT</pubDate></item><item><title><![CDATA[Episode 8: Motor control]]></title><description><![CDATA[<p dir="auto">I will be using a dedicated motor driver IC to control the direction and speed of a DC motor via a virtual joystick widget.</p>
<p dir="auto"><strong>I will be using GUI-O Bluetooth Low Energy (LE) connection, but the example can be easily be ported to other connection types.</strong></p>
<p dir="auto"><strong>Software prerequisites:</strong></p>
<ul>
<li>
<p dir="auto">Arduino IDE (<a href="https://www.arduino.cc/en/software" rel="nofollow ugc">https://www.arduino.cc/en/software</a>)</p>
</li>
<li>
<p dir="auto">ESP32 Arduino board support, if using ESP32 based board (see <a href="https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html" rel="nofollow ugc">https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html</a>)</p>
</li>
<li>
<p dir="auto">GUI-O design tool (<a href="https://www.gui-o.com/design-tool" rel="nofollow ugc">https://www.gui-o.com/design-tool</a>)</p>
</li>
<li>
<p dir="auto">GUI-O application (<a href="https://play.google.com/store/apps/details?id=com.guio.guioapp" rel="nofollow ugc">https://play.google.com/store/apps/details?id=com.guio.guioapp</a>)</p>
</li>
<li>
<p dir="auto">For additional information about the GUI-O application, download the developer manual from <a href="https://www.gui-o.com/" rel="nofollow ugc">https://www.gui-o.com/</a></p>
</li>
</ul>
<p dir="auto"><strong>Components needed:</strong></p>
<ul>
<li>ESP32-WROOM-32 (or any other Arduino supported Bluetooth Low Energy capable board)</li>
<li>L239D motor driver</li>
<li>Small DC motor</li>
</ul>
<p dir="auto"><strong>The entire tutorial is split into various steps. All necessary information is given in each step</strong>.</p>
<h3>0. DESIGN THE GUI (optional)</h3>
<p dir="auto">The best way to create a GUI layout is to use GUI-O live designer tool.</p>
<p dir="auto">Note that the Arduino source code already includes the necessary commands, so this step is not needed, unless you want to make some visual adjustments. If you make adjustments, please include the generated ASCII code in the Arduino source code (see section 1. UPLOAD THE SOURCE CODE).</p>
<p dir="auto">First, you need to establish a TCP/IP connection between the designer tool and GUI-O application:</p>
<ol>
<li>Determine the local IP address of your PC's network interface (WiFi or Ethernet)</li>
</ol>
<ul>
<li>Under Windows, open the command prompt, enter <code>ipconfig</code> and press Enter</li>
<li>Under Linux, open the terminal, enter <code>ifconfig</code> and press Enter</li>
</ul>
<ol start="2">
<li>
<p dir="auto">Open GUI-O application and open settings menu. Select "Connections -&gt; Ethernet" and create a new device with IP address (determined from 1.) and any port between 49152 - 65535</p>
</li>
<li>
<p dir="auto">Open GUI-O designer and select "TCP/IP connection" tab. Set the IP address and port. Both values must match the device settings created within the GUI-O application. Click "Start server" button.</p>
</li>
<li>
<p dir="auto">Within the GUI-O application, tap the created device and wait for successful connection.</p>
</li>
<li>
<p dir="auto">In the GUI-O designer, select "File -&gt; Load designer file" and load the <a href="https://drive.google.com/uc?export=download&amp;id=1DkjQxhmYRP648PWpWkkzIkkKQ9fP2m4h" rel="nofollow ugc">MotorControl.gdf</a> design file. Make the desired adjustments, if necessary. Copy / replace the GUI-O commands into the Arduino source code (see section 1. UPLOAD THE SOURCE CODE).</p>
</li>
</ol>
<h3>1. CONNECT THE COMPONENTS</h3>
<p dir="auto">Connecting the components is straightforward. "D25" pin is used to set the motor speed (via PWM output), while pins "D33" and "D32" are used to control the motor direction.</p>
<p dir="auto"><img src="https://i.imgur.com/7K6T1A3l.png" alt="schematic.png" class=" img-fluid img-markdown" /></p>
<h3>2. UPLOAD THE SOURCE CODE</h3>
<p dir="auto">The source code has inline comments, describing the important parts of the code. You can copy the source code from the snippet below, or download it <a href="https://drive.google.com/uc?export=download&amp;id=1Qpz56xL1MwUeeys3x-ClOHt7XciMWqO1" rel="nofollow ugc">here</a>.</p>
<p dir="auto">Upload the code to your board (make sure that the correct board and upload port are selected). Reset the board after upload.</p>
<pre><code>/*
 * GUI-O Motor control Bluetooth example (using ESP32-WROOM-32)
 *
 * Copyright (C) 2022, kl3m3n
 * last updated on 3.12.2022
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include &lt;BLEDevice.h&gt;
#include &lt;BLEServer.h&gt;
#include &lt;BLEUtils.h&gt;
#include &lt;BLE2902.h&gt;

namespace uuid {
  static const char *SERVICE_UUID = "6E400001-B5A3-F393-E0A9-E50E24DCCA9E";
  static const char *RX_CHARACTERISTIC_UUID = "6E400002-B5A3-F393-E0A9-E50E24DCCA9E";
  static const char *TX_CHARACTERISTIC_UUID = "6E400003-B5A3-F393-E0A9-E50E24DCCA9E";
} // namespace uuid

// forward declare parser for incoming messages
void parseGuioMsg(const String &amp;msg);

// setup done flag
bool setupDone = false;

// setup motor control pins
const int enablePin = 25;
const int inPin_1 = 32;
const int inPin_2 = 33;
// for controlling motor speed...
const double PWM_FREQ = 1000.0;
const uint8_t PWM_BITS = 8;
const uint8_t PWM_CHANNEL = 0;

// custom handling of server callbacks
class CustomBLEServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
      Serial.println("Connected!");
    };
    void onDisconnect(BLEServer* pServer) {
      Serial.println("Disconnected!");
      
      // restart advertising after disconnect, otherwise GUI-O cannot re-connect
      if(setupDone) {
        // restart advertising on disconnect
        delay(500);
        pServer-&gt;startAdvertising(); 
      }
    }
};

// custom handling of characteristic callbacks
class CustomBLECharacteristicCallbacks: public BLECharacteristicCallbacks {
  void onWrite(BLECharacteristic *pCharacteristic) {
    std::string msg = pCharacteristic-&gt;getValue();
    
    // parse message string
    parseGuioMsg(String(msg.c_str()));
  }      
};

// global ptr
BLECharacteristic *pTxCharacteristic;

void setup() {
  // debug output
  Serial.begin(115200);

  // motor control setup (speed, direction)
  ledcSetup(PWM_CHANNEL, PWM_FREQ, PWM_BITS);
  ledcAttachPin(enablePin, PWM_CHANNEL);
  pinMode(inPin_1, OUTPUT);
  pinMode(inPin_2, OUTPUT);

  // create device
  BLEDevice::init("MotorControl");
  // create server and register callback
  BLEServer *pServer = BLEDevice::createServer();
  pServer-&gt;setCallbacks(new CustomBLEServerCallbacks());
  // create service
  BLEService *pService = pServer-&gt;createService(uuid::SERVICE_UUID);

  // crate Tx characteristic and add descriptor
  pTxCharacteristic = pService-&gt;createCharacteristic(uuid::TX_CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_NOTIFY);
  pTxCharacteristic-&gt;addDescriptor(new BLE2902());
  
  // crate Rx characteristic and register callback
  BLECharacteristic *pRxCharacteristic = pService-&gt;createCharacteristic(uuid::RX_CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_WRITE | BLECharacteristic::PROPERTY_WRITE_NR);
  pRxCharacteristic-&gt;setCallbacks(new CustomBLECharacteristicCallbacks());

  // start the service and start advertising
  pService-&gt;start();
  pServer-&gt;getAdvertising()-&gt;start();

  // setup done flag
  setupDone = true;
}

void loop() {
  
}

void sendMsg(const String &amp;msg) {
  pTxCharacteristic-&gt;setValue(std::string(msg.c_str()));
  pTxCharacteristic-&gt;notify();
  delay(50);
}

void parseGuioMsg(const String &amp;msg) {
  if(msg.startsWith("@init")) {
    Serial.println("GUI-O app is requesting INITIALIZATION!");

    // clear screen and set background
    sendMsg("@cls\r\n");
    sendMsg("@guis BGC:#FFFFFF\r\n");
    delay(100);

    // initialize GUI
    sendMsg("|LB UID:title X:50 Y:20 FSZ:4 FFA:\"font8\" TXT:\"Motor&lt;br&gt;control\"\r\n");
    sendMsg("|JOY UID:ctrl X:50 Y:50 W:60 BGC:#00FFFFFF SHE:1 SHC:#806D9DC5 BTH:0.25\r\n");
    sendMsg("|LB UID:dir X:50 Y:75 FGC:#000000 SHE:1 FSZ:5 TXT:\"n/a\"\r\n");
    sendMsg("|LB UID:details X:50 Y:90 FSZ:2 TXT:\"GUI-O motor control&lt;br&gt;demonstration by kl3m3n\"\r\n");
  }
  else if(msg.startsWith("@ctrl")) {
    const auto s_idx = msg.indexOf(' ');
    const auto e_idx = msg.lastIndexOf(' ');
    
    if(s_idx &gt; 0 &amp;&amp; e_idx &gt; 0) {
      String xDirStr = msg.substring(s_idx + 1, e_idx); xDirStr.trim();
      // "convert" values between 0.0 to 1.0 / -1.0 to percent 0 to 100 / -100 (two decimal places, round...)
      const int8_t motorSpeed = static_cast&lt;int8_t&gt;(roundf(xDirStr.toFloat() * 100.0));

      Serial.print("Motor direction: ");
      Serial.print(motorSpeed &gt; 0 ? "CW" : "CCW");
      Serial.print(", speed [%]: ");
      Serial.println(abs(motorSpeed));
      
      // determine direction
      if(motorSpeed &gt; 0) {
        digitalWrite(inPin_1, HIGH);
        digitalWrite(inPin_2, LOW);  
        // update label
        sendMsg("@dir TXT:\"CW\"\r\n");
      }
      else if(motorSpeed &lt; 0) {
        digitalWrite(inPin_1, LOW);
        digitalWrite(inPin_2, HIGH);
        // update label
        sendMsg("@dir TXT:\"CCW\"\r\n");
      }
      else
        sendMsg("@dir TXT:\"OFF\"\r\n");      

      // map motor speed to duty cycle for speed control
      ledcWrite(PWM_CHANNEL, map(abs(motorSpeed), 0, 100, 0, 255));
    }    
  }    
}
</code></pre>
<h3>3. ESTABLISH CONNECTION</h3>
<p dir="auto">Open GUI-O application and navigate to settings menu. Select "Connections -&gt; Bluetooth LE and IoT" and search for devices (enable Bluetooth and Location services, if prompted). Tap on the "MotorControl" device, select <strong>Nordic UART service</strong> and wait for successful connection (confirm device pairing if prompted).</p>
<p dir="auto">Close the settings menu and press the <strong>Initialize</strong> button (see image below) from the GUI-O application home screen.</p>
<p dir="auto"><img src="https://i.imgur.com/DDEHAR7l.jpg" alt="initialize_button.jpg" class=" img-fluid img-markdown" /></p>
<h3>4. THE RESULT</h3>
<p dir="auto">Image below shows the result (screen capture) on my Android device after pressing the "Initialize" button. Motor direction and speed is controlled by the virtual joystick position (only in horizontal direction). If the joystick is pushed all the way to the right (or left), the speed of the motor is at its maximum. When in this position, pushing the joystick up or down decreases the speed of the motor.</p>
<p dir="auto"><img src="https://i.imgur.com/FijciOSl.jpg" alt="screen.jpg" class=" img-fluid img-markdown" /></p>
<hr />
<p dir="auto">If you have any questions or run into any problems, please let me know!</p>
<p dir="auto">Best regards,<br />
kl3m3n</p>
]]></description><link>https://forum.gui-o.com/topic/93/episode-8-motor-control</link><guid isPermaLink="true">https://forum.gui-o.com/topic/93/episode-8-motor-control</guid><dc:creator><![CDATA[kl3m3n]]></dc:creator><pubDate>Sun, 04 Dec 2022 11:29:22 GMT</pubDate></item><item><title><![CDATA[Episode 7 (intermezzo): GUI-O live designer]]></title><description><![CDATA[<p dir="auto">In this episode, I will show how to simply (and quickly) prototype a graphical user interface (GUI) using <strong>GUI-O application</strong> and <strong>GUI-O designer</strong>.</p>
<p dir="auto"><strong>Software prerequisites:</strong></p>
<ul>
<li>
<p dir="auto">GUI-O design tool (<a href="https://www.gui-o.com/design-tool" rel="nofollow ugc">https://www.gui-o.com/design-tool</a>)</p>
</li>
<li>
<p dir="auto">GUI-O application (<a href="https://play.google.com/store/apps/details?id=com.guio.guioapp" rel="nofollow ugc">https://play.google.com/store/apps/details?id=com.guio.guioapp</a>)</p>
</li>
<li>
<p dir="auto">For additional information about the GUI-O application, download the developer manual from <a href="https://www.gui-o.com/" rel="nofollow ugc">https://www.gui-o.com/</a></p>
</li>
</ul>
<h3>What is GUI-O designer?</h3>
<p dir="auto">GUI-O designer is a PC tool (available on Windows and Linux) that helps you build graphical user interfaces on Android smart phones or tablets. It generates the necessary GUI initialization commands (in ASCII format), which can be included into any project's source code.</p>
<h3>How does it work?</h3>
<p dir="auto">GUI-O designer works in "live" mode - all changes to the widgets' properties are immediately reflected on the Android device. Two communication options are available:</p>
<p dir="auto"><strong>1. TCP/IP</strong><br />
This is the simplest approach as (in general), no additional hardware is needed. The GUI-O designer spawns a server using the IP address of the network interface (WiFi or Ethernet), listening on a specified port. The GUI-O application must then use the "Ethernet" connection type, specifying the IP address and port of the server. Both devices (PC and Android) must be on the same local network.</p>
<p dir="auto"><strong>2. Serial port</strong><br />
In this case, a serial device such as USB Serial Bluetooth is required in order to connect to the GUI-O application (see wiring diagram below). Note that any other USB Serial device can also be used, as long as it can be connected to the GUI-O application - check out the manual to see which connection types are supported by the application.</p>
<h3>Getting started</h3>
<p dir="auto">Note that I will be using the TCP/IP communication option as no additional hardware is required in this case and is therefore easier to set up.</p>
<p dir="auto">Please watch the video tutorial below to see GUI-O designer in action. All necessary  steps are also described below.</p>
<p dir="auto"></p><div class="video-embed"><iframe allowfullscreen src="//www.youtube.com/embed/I9b5iYuNEGY"></iframe></div><p></p>
<p dir="auto"><strong>Step 1: Setup connection</strong></p>
<p dir="auto">Follow the steps below to setup the connection between the GUI-O designer and GUI-O application:</p>
<ol>
<li>
<p dir="auto">Determine the IP address of your network interface:</p>
<ul>
<li>
<p dir="auto">for Windows, open the command prompt (cmd) and use "ipconfig" command to display the IP address of the WiFi (or Ethernet) interface on your local network</p>
</li>
<li>
<p dir="auto">for Linux, open the terminal and use "ifconfig" command to display the IP address of the WiFi (or Ethernet) interface on your local network</p>
</li>
</ul>
</li>
<li>
<p dir="auto">Open the GUI-O designer. Under Windows, run "guiodesigner.exe" and under Linux, run "guiodesigner" script.</p>
</li>
<li>
<p dir="auto">Enter the IP address and arbitrary (unused) port number in the range between 49152 - 65535.</p>
</li>
<li>
<p dir="auto">Press "<strong>Start server</strong>" button.</p>
</li>
<li>
<p dir="auto">Start the GUI-O application, open settings menu and select "Connections". Select "Ethernet" connection type and create a new device using the same IP address and port number as above.</p>
</li>
<li>
<p dir="auto">Tap on the newly created device to connect GUI-O application client to the GUI-O designer server.</p>
</li>
</ol>
<p dir="auto"><strong>Step 2: Start designing</strong></p>
<p dir="auto">After the successful connection is made, widget and hardware objects can be created and this is immediately reflected on the Android device. For each created object, numerous properties can be modified.</p>
<p dir="auto"><strong>Step 3: Copy the design to your project</strong></p>
<p dir="auto">The initialization commands are displayed in the <strong>GUI-O command</strong> window. Commands need to be included into your project's source code and sent to the GUI-O application via any of the supported interfaces, whenever the initialization request (<strong>@init</strong>) is made. Additionally, your project's code must handle all user events that are triggered by the GUI-O application.</p>
<hr />
<p dir="auto">As always - if you have any questions or run into any problems, please let me know!</p>
<p dir="auto">Best regards,<br />
kl3m3n</p>
]]></description><link>https://forum.gui-o.com/topic/92/episode-7-intermezzo-gui-o-live-designer</link><guid isPermaLink="true">https://forum.gui-o.com/topic/92/episode-7-intermezzo-gui-o-live-designer</guid><dc:creator><![CDATA[kl3m3n]]></dc:creator><pubDate>Mon, 28 Nov 2022 08:41:42 GMT</pubDate></item><item><title><![CDATA[Episode 6: Ultrasonic ranging]]></title><description><![CDATA[<p dir="auto">I will be using an ultrasonic distance sensor (HC-SR04) to measure the distance to an arbitrary object. The display will show the object distance in centimeters and a graphical indicator denoting the proximity status.</p>
<p dir="auto"><strong>I will be using GUI-O IoT (MQTT) connection, but the example can be easily be ported to other connection types.</strong></p>
<p dir="auto"><strong>Software prerequisites:</strong></p>
<ul>
<li>
<p dir="auto">Arduino IDE (<a href="https://www.arduino.cc/en/software" rel="nofollow ugc">https://www.arduino.cc/en/software</a>)</p>
</li>
<li>
<p dir="auto">ESP32 Arduino board support, if using ESP32 based board (see <a href="https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html" rel="nofollow ugc">https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html</a>)</p>
</li>
<li>
<p dir="auto">Arduino Client for MQTT(<a href="https://github.com/knolleary/pubsubclient" rel="nofollow ugc">https://github.com/knolleary/pubsubclient</a>)<br />
You can follow the setup instructions or directly download and include the <strong><a href="https://drive.google.com/uc?export=download&amp;id=1yRJCDFR2xQDodyIA_lqKfcYdU6pAFy1C" rel="nofollow ugc">PubSubClient.zip</a></strong> library within the Arduino IDE (Sketch -&gt; Include Library -&gt; Add .ZIP library)</p>
</li>
<li>
<p dir="auto">GUI-O design tool (<a href="https://www.gui-o.com/design-tool" rel="nofollow ugc">https://www.gui-o.com/design-tool</a>)</p>
</li>
<li>
<p dir="auto">GUI-O application (<a href="https://play.google.com/store/apps/details?id=com.guio.guioapp" rel="nofollow ugc">https://play.google.com/store/apps/details?id=com.guio.guioapp</a>)</p>
</li>
<li>
<p dir="auto">For additional information about the GUI-O application, download the developer manual from <a href="https://www.gui-o.com/" rel="nofollow ugc">https://www.gui-o.com/</a></p>
</li>
</ul>
<p dir="auto"><strong>Components needed:</strong></p>
<ul>
<li>ESP32-WROOM-32 (or any other Arduino supported WiFi capable board; see <a href="https://github.com/knolleary/pubsubclient#compatible-hardware" rel="nofollow ugc">https://github.com/knolleary/pubsubclient#compatible-hardware</a> for compatible hardware)</li>
<li>HC-SR04 ultrasonic distance sensor</li>
</ul>
<p dir="auto"><strong>The entire tutorial is split into various steps. All necessary information is given in each step</strong>.</p>
<h3>0. DESIGN THE GUI (optional)</h3>
<p dir="auto">The best way to create a GUI layout is to use GUI-O live designer tool.</p>
<p dir="auto">Note that the Arduino source code already includes the necessary commands, so this step is not needed, unless you want to make some visual adjustments. If you make adjustments, please include the generated ASCII code in the Arduino source code (see section 3. MODIFY AND UPLOAD THE SOURCE CODE).</p>
<p dir="auto">First, you need to establish a TCP/IP connection between the designer tool and GUI-O application:</p>
<ol>
<li>Determine the local IP address of your PC's network interface (WiFi or Ethernet)</li>
</ol>
<ul>
<li>Under Windows, open the command prompt, enter <code>ipconfig</code> and press Enter</li>
<li>Under Linux, open the terminal, enter <code>ifconfig</code> and press Enter</li>
</ul>
<ol start="2">
<li>
<p dir="auto">Open GUI-O application and open settings menu. Select "Connections -&gt; Ethernet" and create a new device with IP address (determined from 1.) and any port between 49152 - 65535</p>
</li>
<li>
<p dir="auto">Open GUI-O designer and select "TCP/IP connection" tab. Set the IP address and port. Both values must match the device settings created within the GUI-O application. Click "Start server" button.</p>
</li>
<li>
<p dir="auto">Within the GUI-O application, tap the created device and wait for successful connection.</p>
</li>
<li>
<p dir="auto">In the GUI-O designer, select "File -&gt; Load designer file" and load the <a href="https://drive.google.com/uc?export=download&amp;id=14IkzODVAYuH7yrAVqHAv7yXFbNlFxBla" rel="nofollow ugc">UltrasonicRanging.gdf</a> design file. Make the desired adjustments, if necessary. Copy / replace the GUI-O commands into the Arduino source code (see section 3. MODIFY AND UPLOAD THE SOURCE CODE).</p>
</li>
</ol>
<h3>1.  CONNECT THE COMPONENTS</h3>
<p dir="auto">Connecting the components is straightforward. The "D32" and "D33" are GPIO pins on ESP32.</p>
<p dir="auto"><img src="https://i.imgur.com/RyXbjHMl.png" alt="schematic.png" class=" img-fluid img-markdown" /></p>
<h3>2. CREATE A UNIQUE MQTT CHANNEL</h3>
<p dir="auto">Open GUI-O application and navigate to settings menu. Select "Connections -&gt; IoT" and add a new device. After adding the device, note the <strong>In</strong> and <strong>Out</strong> token (you can share this tokens e.g., to your e-mail by pressing the "share" button).</p>
<p dir="auto">Finally, press "Connect" menu entry to establish the connection with the MQTT server.</p>
<h3>3. MODIFY AND UPLOAD THE SOURCE CODE</h3>
<p dir="auto">The source code has inline comments, describing the important parts of the code. You can copy the source code from the snippet below, or download it <a href="https://drive.google.com/uc?export=download&amp;id=1rtjLrUITkyMcy7oU08iksLUzuU0eQhHS" rel="nofollow ugc">here</a>.</p>
<p dir="auto">The only thing that needs to be done is to set the <strong>ssid</strong> and <strong>password</strong> of your router and the unique <strong>In</strong> and <strong>Out</strong> channels that were generated by the GUI-O application (see section 2. CREATE A UNIQUE MQTT CHANNEL).</p>
<p dir="auto">After setting these values, upload the code to your board (make sure that the correct board and upload port are selected). Reset the board after upload.</p>
<pre><code>/*
 * GUI-O Ultrasonic ranging MQTT example (using ESP32-WROOM-32)
 *
 * Copyright (C) 2022, kl3m3n
 * last updated on 19.11.2022
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include &lt;WiFi.h&gt;
#include &lt;PubSubClient.h&gt;

static const char *ssid = "&lt;ssid&gt;"; // router name
static const char *pass = "&lt;pass&gt;"; // router password

static const char *mqttServer = "mqtt.gui-o.com";   // host name
static const char *mqttUser = "gui-o-mqtt-generic"; // user name
static const char *mqttPass = "lqXeZpv5VJyv0XBT";   // password

// IMPORTANT NOTE: if optional user name was specified when adding a new IoT device,
// the user name should also be included when setting the topics (e.g., "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/&lt;user_name&gt;")
static const char *Out = "&lt;Out&gt;"; // GUI-O app publish topic
static const char *In = "&lt;In&gt;";  // GUI-O app subscribe topic

// mqtt client
WiFiClient wiFiClient;
PubSubClient mqttClient(wiFiClient);

// forward declare functions for mqtt messages handling
void mqttCallback(char* topic, byte* message, unsigned int length);
void parseGuioMsg(const String &amp;msg);

char buf[200];

// setup ranging settings
const int triggerPin = 32;
const int echoPin = 33;
// speed of sound in m/us
constexpr float soundSpeedUs = 340.0 / 1000000.0;

// sampling
unsigned long startTimestampMsec, currentTimestampMsec;
const unsigned long readIntervalMsec = 250; // milliseconds

void setup() {
  // debug output
  Serial.begin(115200);

  // setup pins
  pinMode(triggerPin, OUTPUT);
  pinMode(echoPin, INPUT);
  
  // connect WiFi (keep trying...)
  Serial.print("Connecting to ");
  Serial.println(ssid);
  
  WiFi.begin(ssid, pass);
  while(WiFi.status() != WL_CONNECTED) { 
    Serial.print(".");
    delay(500); 
  }
  
  Serial.println("WiFi connected!"); 
  
  // setup mqtt
  mqttClient.setServer(mqttServer, 1883);
  mqttClient.setCallback(mqttCallback);

  startTimestampMsec = millis();
}

void loop() {
  while(!mqttClient.connected()) {
    Serial.println("MQTT connecting...");

    // mqtt client id is the mac address (AABBCCDDEEFF)
    char mqttClientId[15];    
    uint8_t mac[6];
    WiFi.macAddress(mac);

    snprintf(mqttClientId, sizeof(mqttClientId), "%02x%02x%02x%02x%02x%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);

    if(mqttClient.connect(mqttClientId, mqttUser, mqttPass)) {
      Serial.println("MQTT connected!");
      mqttClient.subscribe(&amp;Out[0]);
    }
    else {
      Serial.print("MQTT connection failed (");
      Serial.print(mqttClient.state());
      Serial.println(")! Retrying...");      
      delay(2500);
    }
  }
  mqttClient.loop();

  // get and display temperature 
  currentTimestampMsec = millis();
  
  if(currentTimestampMsec - startTimestampMsec &gt; readIntervalMsec) {
    // pull low, just in case...
    digitalWrite(triggerPin, LOW);
    delayMicroseconds(2);
    // output high level to trigger pin for a short duration
    digitalWrite(triggerPin, HIGH);
    delayMicroseconds(10); // as per datasheet
    digitalWrite(triggerPin, LOW);

    // get distance in cm
    unsigned long pingTime = pulseIn(echoPin, HIGH); //, pingTimeout);
    const float distance = (static_cast&lt;float&gt;(pingTime) * soundSpeedUs * 0.5) * 100.0;

    auto pubBuf = []() { mqttClient.publish(&amp;In[0], &amp;buf[0]); };

    // update distance indicator (keeping implementation simple, though not very readable...)
    // too close
    if(distance &lt; 20.0) {
      snprintf(buf, sizeof(buf), "@dist TXT:\"%.1f cm\" FGC:#FF0000\r\n", distance);
      pubBuf();
      //
      snprintf(buf, sizeof(buf), "@distInd IDXC:\"0:#00FF00,1:#00FF00,2:#FFA500,3:#FFA500,4:#FF0000\"\r\n");
      pubBuf();
    }
    // very close
    else if(distance &lt; 30.0) {
      snprintf(buf, sizeof(buf), "@dist TXT:\"%.1f cm\" FGC:#FFA500\r\n", distance);
      pubBuf();
      //
      snprintf(buf, sizeof(buf), "@distInd IDXC:\"0:#00FF00,1:#00FF00,2:#FFA500,3:#FFA500,4:#D3D3D3\"\r\n");
      pubBuf();
    }
    // close
    else if(distance &lt; 50.0) {
      snprintf(buf, sizeof(buf), "@dist TXT:\"%.1f cm\" FGC:#FFA500\r\n", distance);
      pubBuf();
      //
      snprintf(buf, sizeof(buf), "@distInd IDXC:\"0:#00FF00,1:#00FF00,2:#FFA500,3:#D3D3D3,4:#D3D3D3\"\r\n");
      pubBuf();
    }
    // far
    else if(distance &lt; 70.0) {
      snprintf(buf, sizeof(buf), "@dist TXT:\"%.1f cm\" FGC:#00FF00\r\n", distance);
      pubBuf();
      //
      snprintf(buf, sizeof(buf), "@distInd IDXC:\"0:#00FF00,1:#00FF00,2:#D3D3D3,3:#D3D3D3,4:#D3D3D3\"\r\n");
      pubBuf();
    }
    // very far
    else {
      snprintf(buf, sizeof(buf), "@dist TXT:\"%.1f cm\" FGC:#00FF00\r\n", distance);
      pubBuf();
      //
      snprintf(buf, sizeof(buf), "@distInd IDXC:\"0:#00FF00,1:#D3D3D3,2:#D3D3D3,3:#D3D3D3,4:#D3D3D3\"\r\n");
      pubBuf();
    }

    Serial.print("ping time = ");
    Serial.print(pingTime);
    Serial.println(" us");
    Serial.print("distance = ");
    Serial.print(distance);
    Serial.println(" cm\n");

    // reset read interval
    startTimestampMsec = millis();
  }
}

// mqtt callback function
void mqttCallback(char* topic, byte* message, unsigned int length) {
  // build message string
  String msg;
  for(int i = 0; i &lt; length; i++) {
    msg += (char) message[i];
  }
  // parse message string
  parseGuioMsg(msg);
}

void parseGuioMsg(const String &amp;msg) {
  if(msg.startsWith("@init")) {
    Serial.println("GUI-O app is requesting INITIALIZATION!");

    // clear screen and set background
    mqttClient.publish(&amp;In[0], "@cls\r\n");
    mqttClient.publish(&amp;In[0], "@guis BGC:#FFFFFF\r\n");
    delay(100);

    // initialize GUI
    mqttClient.publish(&amp;In[0], "|LB UID:title X:50 Y:20 FSZ:4 FFA:\"font8\" TXT:\"Ultrasonic&lt;br&gt;ranging\"\r\n");
    mqttClient.publish(&amp;In[0], "|RECG UID:distInd X:50 Y:50 W:30 H:20 HIW:0 ROWS:5 COLS:1 SPC:0.5\r\n");
    mqttClient.publish(&amp;In[0], "|LB UID:dist X:50 Y:70 FGC:#4C4C4C FSZ:6 TXT:\"n/a\"\r\n");
    mqttClient.publish(&amp;In[0], "|LB UID:details X:50 Y:90 FSZ:2 TXT:\"GUI-O ultrasonic ranging&lt;br&gt;demonstration by kl3m3n\"\r\n");

    // must send as a new message (minor GUI-O application bug)
    mqttClient.publish(&amp;In[0], "@distInd IDXC:\"0:#D3D3D3,1:#D3D3D3,2:#D3D3D3,3:#D3D3D3,4:#D3D3D3\"\r\n");
  }  
}
</code></pre>
<h3>4. ESTABLISH CONNECTION</h3>
<p dir="auto">Make sure that the GUI-O application is connected to the MQTT server.<br />
Also make sure that the ESP32 board (or other Arduino supported board) is connected to the MQTT server (you can check this by observing the serial debug messages using the Arduino serial monitor).</p>
<p dir="auto">Press the <strong>Initialize</strong> button (see image below) from the GUI-O application home screen.</p>
<p dir="auto"><img src="https://i.imgur.com/DDEHAR7l.jpg" alt="initialize_button.jpg" class=" img-fluid img-markdown" /></p>
<h3>5. THE RESULT</h3>
<p dir="auto">Image below shows the result (screen capture) on my Android device after pressing the "Initialize" button. The bars graphically represent the object proximity based on some predefined intervals (green = far, orange = close, red = collision imminent).</p>
<p dir="auto"><img src="https://i.imgur.com/aSpkiS9l.jpg" alt="screen.jpg" class=" img-fluid img-markdown" /></p>
<hr />
<p dir="auto">If you have any questions or run into any problems, please let me know!</p>
<p dir="auto">Best regards,<br />
kl3m3n</p>
]]></description><link>https://forum.gui-o.com/topic/91/episode-6-ultrasonic-ranging</link><guid isPermaLink="true">https://forum.gui-o.com/topic/91/episode-6-ultrasonic-ranging</guid><dc:creator><![CDATA[kl3m3n]]></dc:creator><pubDate>Sun, 20 Nov 2022 12:09:28 GMT</pubDate></item><item><title><![CDATA[Episode 5: Humidity and temperature reader]]></title><description><![CDATA[<p dir="auto">I will be using a DHT11 sensor to read and display humidity and ambient temperature. Using a drop-down selector, the indicators for each quantity can be shown or hidden.</p>
<p dir="auto"><strong>I will be using GUI-O IoT (MQTT) connection, but the example can be easily be ported to other connection types.</strong></p>
<p dir="auto"><strong>Software prerequisites:</strong></p>
<ul>
<li>
<p dir="auto">Arduino IDE (<a href="https://www.arduino.cc/en/software" rel="nofollow ugc">https://www.arduino.cc/en/software</a>)</p>
</li>
<li>
<p dir="auto">ESP32 Arduino board support, if using ESP32 based board (see <a href="https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html" rel="nofollow ugc">https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html</a>)</p>
</li>
<li>
<p dir="auto">Arduino Client for MQTT(<a href="https://github.com/knolleary/pubsubclient" rel="nofollow ugc">https://github.com/knolleary/pubsubclient</a>)<br />
You can follow the setup instructions or directly download and include the <strong><a href="https://drive.google.com/uc?export=download&amp;id=1yRJCDFR2xQDodyIA_lqKfcYdU6pAFy1C" rel="nofollow ugc">PubSubClient.zip</a></strong> library within the Arduino IDE (Sketch -&gt; Include Library -&gt; Add .ZIP library)</p>
</li>
<li>
<p dir="auto">Adafruit DHT sensor library (<a href="https://github.com/adafruit/DHT-sensor-library" rel="nofollow ugc">https://github.com/adafruit/DHT-sensor-library</a>). Note the library dependencies section!<br />
You can follow the setup instructions or directly download and include the <strong><a href="https://drive.google.com/uc?export=download&amp;id=1cthV8WazwB34-0pVtEspgIvXBe_TLseX" rel="nofollow ugc">DHT_sensor_library.zip</a></strong> and <strong><a href="https://drive.google.com/uc?export=download&amp;id=1MkA3sK6R8SXPM4LJ6AmcOD3JrjA-OiOy" rel="nofollow ugc">Adafruit_Unified_Sensor.zip</a></strong> libraries within the Arduino IDE (Sketch -&gt; Include Library -&gt; Add .ZIP library)</p>
</li>
<li>
<p dir="auto">GUI-O design tool (<a href="https://www.gui-o.com/design-tool" rel="nofollow ugc">https://www.gui-o.com/design-tool</a>)</p>
</li>
<li>
<p dir="auto">GUI-O application (<a href="https://play.google.com/store/apps/details?id=com.guio.guioapp" rel="nofollow ugc">https://play.google.com/store/apps/details?id=com.guio.guioapp</a>)</p>
</li>
<li>
<p dir="auto">For additional information about the GUI-O application, download the developer manual from <a href="https://www.gui-o.com/" rel="nofollow ugc">https://www.gui-o.com/</a></p>
</li>
</ul>
<p dir="auto"><strong>Components needed:</strong></p>
<ul>
<li>ESP32-WROOM-32 (or any other Arduino supported WiFi capable board; see <a href="https://github.com/knolleary/pubsubclient#compatible-hardware" rel="nofollow ugc">https://github.com/knolleary/pubsubclient#compatible-hardware</a> for compatible hardware)</li>
<li>10k resistor</li>
<li>DHT11 sensor</li>
</ul>
<p dir="auto"><strong>The entire tutorial is split into various steps. All necessary information is given in each step</strong>.</p>
<h3>0. DESIGN THE GUI (optional)</h3>
<p dir="auto">The best way to create a GUI layout is to use GUI-O live designer tool.</p>
<p dir="auto">Note that the Arduino source code already includes the necessary commands, so this step is not needed, unless you want to make some visual adjustments. If you make adjustments, please include the generated ASCII code in the Arduino source code (see section 3. MODIFY AND UPLOAD THE SOURCE CODE).</p>
<p dir="auto">First, you need to establish a TCP/IP connection between the designer tool and GUI-O application:</p>
<ol>
<li>Determine the local IP address of your PC's network interface (WiFi or Ethernet)</li>
</ol>
<ul>
<li>Under Windows, open the command prompt, enter <code>ipconfig</code> and press Enter</li>
<li>Under Linux, open the terminal, enter <code>ifconfig</code> and press Enter</li>
</ul>
<ol start="2">
<li>
<p dir="auto">Open GUI-O application and open settings menu. Select "Connections -&gt; Ethernet" and create a new device with IP address (determined from 1.) and any port between 49152 - 65535</p>
</li>
<li>
<p dir="auto">Open GUI-O designer and select "TCP/IP connection" tab. Set the IP address and port. Both values must match the device settings created within the GUI-O application. Click "Start server" button.</p>
</li>
<li>
<p dir="auto">Within the GUI-O application, tap the created device and wait for successful connection.</p>
</li>
<li>
<p dir="auto">In the GUI-O designer, select "File -&gt; Load designer file" and load the <a href="https://drive.google.com/uc?export=download&amp;id=1O3pIJLwYisRNjIpA1mUTT0WLFKhUNVrT" rel="nofollow ugc">HumidityTemperatureReader.gdf</a> design file. Make the desired adjustments, if necessary. Copy / replace the GUI-O commands into the Arduino source code (see section 3. MODIFY AND UPLOAD THE SOURCE CODE).</p>
</li>
</ol>
<h3>1.  CONNECT THE COMPONENTS</h3>
<p dir="auto">Connecting the components is straightforward.</p>
<p dir="auto"><img src="https://i.imgur.com/mumfEUHl.png" alt="schematic.png" class=" img-fluid img-markdown" /></p>
<h3>2. CREATE A UNIQUE MQTT CHANNEL</h3>
<p dir="auto">Open GUI-O application and navigate to settings menu. Select "Connections -&gt; IoT" and add a new device. After adding the device, note the <strong>In</strong> and <strong>Out</strong> token (you can share this tokens e.g., to your e-mail by pressing the "share" button).</p>
<p dir="auto">Finally, press "Connect" menu entry to establish the connection with the MQTT server.</p>
<h3>3. MODIFY AND UPLOAD THE SOURCE CODE</h3>
<p dir="auto">The source code has inline comments, describing the important parts of the code. You can copy the source code from the snippet below, or download it <a href="https://drive.google.com/uc?export=download&amp;id=16rG3UeeRapQPleDJ2atUMMektT_4YEic" rel="nofollow ugc">here</a>.</p>
<p dir="auto">The only thing that needs to be done is to set the <strong>ssid</strong> and <strong>password</strong> of your router and the unique <strong>In</strong> and <strong>Out</strong> channels that were generated by the GUI-O application (see section 2. CREATE A UNIQUE MQTT CHANNEL).</p>
<p dir="auto">After setting these values, upload the code to your board (make sure that the correct board and upload port are selected). Reset the board after upload.</p>
<pre><code>/*
 * GUI-O Humidity and temperature reader MQTT example (using ESP32-WROOM-32)
 *
 * Copyright (C) 2022, kl3m3n
 * last updated on 12.11.2022
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include &lt;WiFi.h&gt;
#include &lt;PubSubClient.h&gt;
#include &lt;DHT.h&gt;

static const char *ssid = "&lt;ssid&gt;"; // router name
static const char *pass = "&lt;pass&gt;"; // router password

static const char *mqttServer = "mqtt.gui-o.com";   // host name
static const char *mqttUser = "gui-o-mqtt-generic"; // user name
static const char *mqttPass = "lqXeZpv5VJyv0XBT";   // password

// IMPORTANT NOTE: if optional user name was specified when adding a new IoT device,
// the user name should also be included when setting the topics (e.g., "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/&lt;user_name&gt;")
static const char *Out = "&lt;Out&gt;"; // GUI-O app publish topic
static const char *In = "&lt;In&gt;";  // GUI-O app subscribe topic

// mqtt client
WiFiClient wiFiClient;
PubSubClient mqttClient(wiFiClient);

// forward declare functions for mqtt messages handling
void mqttCallback(char* topic, byte* message, unsigned int length);
void parseGuioMsg(const String &amp;msg);

// using DHT11 sensor
char buf[100];
const int dhtPin = 25;
DHT dht(dhtPin, DHT11);

unsigned long startTimestampMsec, currentTimestampMsec;
const unsigned long readIntervalMsec = 2000; // milliseconds

void setup() {
  // debug output
  Serial.begin(115200);

  // dht setup
  dht.begin();
  
  // connect WiFi (keep trying...)
  Serial.print("Connecting to ");
  Serial.println(ssid);
  
  WiFi.begin(ssid, pass);
  while(WiFi.status() != WL_CONNECTED) { 
    Serial.print(".");
    delay(500); 
  }
  
  Serial.println("WiFi connected!"); 
  
  // setup mqtt
  mqttClient.setServer(mqttServer, 1883);
  mqttClient.setCallback(mqttCallback);

  startTimestampMsec = millis();
}

void loop() {
  while(!mqttClient.connected()) {
    Serial.println("MQTT connecting...");

    // mqtt client id is the mac address (AABBCCDDEEFF)
    char mqttClientId[15];    
    uint8_t mac[6];
    WiFi.macAddress(mac);

    snprintf(mqttClientId, sizeof(mqttClientId), "%02x%02x%02x%02x%02x%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);

    if(mqttClient.connect(mqttClientId, mqttUser, mqttPass)) {
      Serial.println("MQTT connected!");
      mqttClient.subscribe(&amp;Out[0]);
    }
    else {
      Serial.print("MQTT connection failed (");
      Serial.print(mqttClient.state());
      Serial.println(")! Retrying...");      
      delay(2500);
    }
  }
  mqttClient.loop();

  currentTimestampMsec = millis();

  if(currentTimestampMsec - startTimestampMsec &gt; readIntervalMsec) {
    // read humidity and temperature (in °C)
    float hum = dht.readHumidity();
    float temp = dht.readTemperature();

    if(!isnan(hum) &amp;&amp; !isnan(temp)) {
      // labels
      snprintf(buf, sizeof(buf), "@hum TXT:\"%.0f %%\"\r\n", hum);
      mqttClient.publish(&amp;In[0], &amp;buf[0]);
      //
      snprintf(buf, sizeof(buf), "@temp TXT:\"%.1f °C\"\r\n", temp);
      mqttClient.publish(&amp;In[0], &amp;buf[0]);
      
      // dial indicators
      snprintf(buf, sizeof(buf), "@humInd VAL:%.0f %%\r\n", hum);
      mqttClient.publish(&amp;In[0], &amp;buf[0]);
      //
      snprintf(buf, sizeof(buf), "@tempInd VAL:%.0f °C\r\n", temp);
      mqttClient.publish(&amp;In[0], &amp;buf[0]);

      Serial.print("H = ");
      Serial.print(hum);
      Serial.println(" %");

      Serial.print("T = ");
      Serial.print(temp);
      Serial.println(" °C");
    }
    
    startTimestampMsec = millis();
  }
}

// mqtt callback function
void mqttCallback(char* topic, byte* message, unsigned int length) {
  // build message string
  String msg;
  for(int i = 0; i &lt; length; i++) {
    msg += (char) message[i];
  }
  // parse message string
  parseGuioMsg(msg);
}

void parseGuioMsg(const String &amp;msg) {
  if(msg.startsWith("@init")) {
    Serial.println("GUI-O app is requesting INITIALIZATION!");

    // clear screen and set background
    mqttClient.publish(&amp;In[0], "@cls\r\n");
    mqttClient.publish(&amp;In[0], "@guis BGC:#FFFFFF\r\n");
    delay(100);

    // initialize GUI
    mqttClient.publish(&amp;In[0], "|DRB UID:display X:50 Y:10 W:50 FGC:#FFFFFF DAL:\"Both,Temperature,Humidity\"\r\n");
    mqttClient.publish(&amp;In[0], "|CB UID:tempInd X:50 Y:35 SFGC:#FF281E IP:\"\" HVAL:40 TXTC:#000000 XTC:4 YTC:0 RCA:0 CE:0 SHT:1\r\n");
    mqttClient.publish(&amp;In[0], "|LB UID:temp X:50 Y:35 FGC:#000000 FSZ:5 FFA:\"font6\" TXT:\"\"\r\n");
    mqttClient.publish(&amp;In[0], "|CB UID:humInd X:50 Y:65 IP:\"\" TXTC:#000000 XTC:4 YTC:0 RCA:0 CE:0 SHT:1\r\n");
    mqttClient.publish(&amp;In[0], "|LB UID:hum X:50 Y:65 FGC:#000000 FSZ:5 FFA:\"font6\" TXT:\"\"\r\n");
    mqttClient.publish(&amp;In[0], "|LB UID:details X:50 Y:90 FSZ:2 TXT:\"GUI-O humidity and temperature&lt;br&gt;reader demonstration by kl3m3n\"\r\n");
  }
  else if(msg.startsWith("@display")) {
    // could do this better, but does the job fine (don't remove the trailing spaces...)
    if(msg.indexOf("Temperature ") &gt;= 0) {
      // show temperature only
      mqttClient.publish(&amp;In[0], "@tempInd VIS:1\r\n");
      mqttClient.publish(&amp;In[0], "@temp VIS:1\r\n");
      //
      mqttClient.publish(&amp;In[0], "@humInd VIS:0\r\n");
      mqttClient.publish(&amp;In[0], "@hum VIS:0\r\n");
    }
    else if(msg.indexOf("Humidity ") &gt;= 0) {
      // show humidity only
      mqttClient.publish(&amp;In[0], "@tempInd VIS:0\r\n");
      mqttClient.publish(&amp;In[0], "@temp VIS:0\r\n");
      //
      mqttClient.publish(&amp;In[0], "@humInd VIS:1\r\n");
      mqttClient.publish(&amp;In[0], "@hum VIS:1\r\n");
    }
    else {
      // show all
      mqttClient.publish(&amp;In[0], "@tempInd VIS:1\r\n");
      mqttClient.publish(&amp;In[0], "@temp VIS:1\r\n");
      //
      mqttClient.publish(&amp;In[0], "@humInd VIS:1\r\n");
      mqttClient.publish(&amp;In[0], "@hum VIS:1\r\n");
    }
  }    
}
</code></pre>
<h3>4. ESTABLISH CONNECTION</h3>
<p dir="auto">Make sure that the GUI-O application is connected to the MQTT server.<br />
Also make sure that the ESP32 board (or other Arduino supported board) is connected to the MQTT server (you can check this by observing the serial debug messages using the Arduino serial monitor).</p>
<p dir="auto">Press the <strong>Initialize</strong> button (see image below) from the GUI-O application home screen.</p>
<p dir="auto"><img src="https://i.imgur.com/DDEHAR7l.jpg" alt="initialize_button.jpg" class=" img-fluid img-markdown" /></p>
<h3>5. THE RESULT</h3>
<p dir="auto">Images below shows the result (screen capture) on my Android device after pressing the "Initialize" button. The humidity and temperature indicators are updated every 2 seconds. The visibility of indicators can be controlled via the drop-down box widget.</p>
<p dir="auto"><img src="https://i.imgur.com/oXmChu3l.jpg" alt="screen0.jpg" class=" img-fluid img-markdown" /></p>
<hr />
<p dir="auto"><img src="https://i.imgur.com/5OKxrIsl.jpg" alt="screen1.jpg" class=" img-fluid img-markdown" /></p>
<hr />
<p dir="auto"><img src="https://i.imgur.com/3i5rlzBl.jpg" alt="screen2.jpg" class=" img-fluid img-markdown" /></p>
<hr />
<p dir="auto">If you have any questions or run into any problems, please let me know!</p>
<p dir="auto">Best regards,<br />
kl3m3n</p>
]]></description><link>https://forum.gui-o.com/topic/90/episode-5-humidity-and-temperature-reader</link><guid isPermaLink="true">https://forum.gui-o.com/topic/90/episode-5-humidity-and-temperature-reader</guid><dc:creator><![CDATA[kl3m3n]]></dc:creator><pubDate>Sat, 12 Nov 2022 20:45:51 GMT</pubDate></item><item><title><![CDATA[Episode 4: Resource downloader]]></title><description><![CDATA[<p dir="auto">This is a simple example that shows how to download videos and images from online resources, which can be incorporated into any application.</p>
<p dir="auto"><strong>I will be using GUI-O IoT (MQTT) connection, but the example can be easily be ported to other connection types.</strong></p>
<p dir="auto"><strong>Software prerequisites:</strong></p>
<ul>
<li>
<p dir="auto">Arduino IDE (<a href="https://www.arduino.cc/en/software" rel="nofollow ugc">https://www.arduino.cc/en/software</a>)</p>
</li>
<li>
<p dir="auto">ESP32 Arduino board support, if using ESP32 based board (see <a href="https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html" rel="nofollow ugc">https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html</a>)</p>
</li>
<li>
<p dir="auto">Arduino Client for MQTT(<a href="https://github.com/knolleary/pubsubclient" rel="nofollow ugc">https://github.com/knolleary/pubsubclient</a>)<br />
You can follow the setup instructions or directly download and include the <strong><a href="https://drive.google.com/uc?export=download&amp;id=1yRJCDFR2xQDodyIA_lqKfcYdU6pAFy1C" rel="nofollow ugc">PubSubClient.zip</a></strong> library within the Arduino IDE (Sketch -&gt; Include Library -&gt; Add .ZIP library)</p>
</li>
<li>
<p dir="auto">GUI-O design tool (<a href="https://www.gui-o.com/design-tool" rel="nofollow ugc">https://www.gui-o.com/design-tool</a>)</p>
</li>
<li>
<p dir="auto">GUI-O application (<a href="https://play.google.com/store/apps/details?id=com.guio.guioapp" rel="nofollow ugc">https://play.google.com/store/apps/details?id=com.guio.guioapp</a>)</p>
</li>
<li>
<p dir="auto">For additional information about the GUI-O application, download the developer manual from <a href="https://www.gui-o.com/" rel="nofollow ugc">https://www.gui-o.com/</a></p>
</li>
</ul>
<p dir="auto"><strong>Components needed:</strong></p>
<ul>
<li>ESP32-WROOM-32 (or any other Arduino supported WiFi capable board; see <a href="https://github.com/knolleary/pubsubclient#compatible-hardware" rel="nofollow ugc">https://github.com/knolleary/pubsubclient#compatible-hardware</a> for compatible hardware)</li>
</ul>
<p dir="auto"><strong>The entire tutorial is split into various steps. All necessary information is given in each step</strong>.</p>
<h3>0. DESIGN THE GUI (optional)</h3>
<p dir="auto">The best way to create a GUI layout is to use GUI-O live designer tool.</p>
<p dir="auto">Note that the Arduino source code already includes the necessary commands, so this step is not needed, unless you want to make some visual adjustments. If you make adjustments, please include the generated ASCII code in the Arduino source code (see section 3. MODIFY AND UPLOAD THE SOURCE CODE).</p>
<p dir="auto">First, you need to establish a TCP/IP connection between the designer tool and GUI-O application:</p>
<ol>
<li>Determine the local IP address of your PC's network interface (WiFi or Ethernet)</li>
</ol>
<ul>
<li>Under Windows, open the command prompt, enter <code>ipconfig</code> and press Enter</li>
<li>Under Linux, open the terminal, enter <code>ifconfig</code> and press Enter</li>
</ul>
<ol start="2">
<li>
<p dir="auto">Open GUI-O application and open settings menu. Select "Connections -&gt; Ethernet" and create a new device with IP address (determined from 1.) and any port between 49152 - 65535</p>
</li>
<li>
<p dir="auto">Open GUI-O designer and select "TCP/IP connection" tab. Set the IP address and port. Both values must match the device settings created within the GUI-O application. Click "Start server" button.</p>
</li>
<li>
<p dir="auto">Within the GUI-O application, tap the created device and wait for successful connection.</p>
</li>
<li>
<p dir="auto">In the GUI-O designer, select "File -&gt; Load designer file" and load the <a href="https://drive.google.com/uc?export=download&amp;id=1XtX-eaSz3huthTYf3ryMkqz7Fos9eawy" rel="nofollow ugc">ResourceDownloader.gdf</a> design file. Make the desired adjustments, if necessary. Copy / replace the GUI-O commands into the Arduino source code (see section 3. MODIFY AND UPLOAD THE SOURCE CODE).</p>
</li>
</ol>
<h3>1. CREATE A UNIQUE MQTT CHANNEL</h3>
<p dir="auto">Open GUI-O application and navigate to settings menu. Select "Connections -&gt; IoT" and add a new device. After adding the device, note the <strong>In</strong> and <strong>Out</strong> token (you can share this tokens e.g., to your e-mail by pressing the "share" button).</p>
<p dir="auto">Finally, press "Connect" menu entry to establish the connection with the MQTT server.</p>
<h3>2. MODIFY AND UPLOAD THE SOURCE CODE</h3>
<p dir="auto">The source code has inline comments, describing the important parts of the code. You can copy the source code from the snippet below, or download it <a href="https://drive.google.com/uc?export=download&amp;id=1mGdb8z5MHfQVXUyWNwYCN1nHXUa0BGx0" rel="nofollow ugc">here</a>.</p>
<p dir="auto">The only thing that needs to be done is to set the <strong>ssid</strong> and <strong>password</strong> of your router and the unique <strong>In</strong> and <strong>Out</strong> channels that were generated by the GUI-O application (see section 2. CREATE A UNIQUE MQTT CHANNEL).</p>
<p dir="auto">After setting these values, upload the code to your board (make sure that the correct board and upload port are selected). Reset the board after upload.</p>
<pre><code>/*
 * GUI-O Resource downloader MQTT example (using ESP32-WROOM-32)
 *
 * Copyright (C) 2022, kl3m3n
 * last updated on 12.11.2022
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include &lt;WiFi.h&gt;
#include &lt;PubSubClient.h&gt;

static const char *ssid = "&lt;ssid&gt;"; // router name
static const char *pass = "&lt;pass&gt;"; // router password

static const char *mqttServer = "mqtt.gui-o.com";   // host name
static const char *mqttUser = "gui-o-mqtt-generic"; // user name
static const char *mqttPass = "lqXeZpv5VJyv0XBT";   // password

// IMPORTANT NOTE: if optional user name was specified when adding a new IoT device,
// the user name should also be included when setting the topics (e.g., "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/&lt;user_name&gt;")
static const char *Out = "&lt;Out&gt;"; // GUI-O app publish topic
static const char *In = "&lt;In&gt;";  // GUI-O app subscribe topic

// mqtt client
WiFiClient wiFiClient;
PubSubClient mqttClient(wiFiClient);

// forward declare functions for mqtt messages handling
void mqttCallback(char* topic, byte* message, unsigned int length);
void parseGuioMsg(const String &amp;msg);

void setup() {
  // debug output
  Serial.begin(115200);
  
  // connect WiFi (keep trying...)
  Serial.print("Connecting to ");
  Serial.println(ssid);
  
  WiFi.begin(ssid, pass);
  while(WiFi.status() != WL_CONNECTED) { 
    Serial.print(".");
    delay(500); 
  }
  
  Serial.println("WiFi connected!"); 
  
  // setup mqtt
  mqttClient.setServer(mqttServer, 1883);
  mqttClient.setCallback(mqttCallback);
}

void loop() {
  while(!mqttClient.connected()) {
    Serial.println("MQTT connecting...");

    // mqtt client id is the mac address (AABBCCDDEEFF)
    char mqttClientId[15];    
    uint8_t mac[6];
    WiFi.macAddress(mac);

    snprintf(mqttClientId, sizeof(mqttClientId), "%02x%02x%02x%02x%02x%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);

    if(mqttClient.connect(mqttClientId, mqttUser, mqttPass)) {
      Serial.println("MQTT connected!");
      mqttClient.subscribe(&amp;Out[0]);
    }
    else {
      Serial.print("MQTT connection failed (");
      Serial.print(mqttClient.state());
      Serial.println(")! Retrying...");      
      delay(2500);
    }
  }
  mqttClient.loop();
}

// mqtt callback function
void mqttCallback(char* topic, byte* message, unsigned int length) {
  // build message string
  String msg;
  for(int i = 0; i &lt; length; i++) {
    msg += (char) message[i];
  }
  // parse message string
  parseGuioMsg(msg);
}

void parseGuioMsg(const String &amp;msg) {
  if(msg.startsWith("@init")) {
    Serial.println("GUI-O app is requesting INITIALIZATION!");

    // clear screen and set background
    mqttClient.publish(&amp;In[0], "@cls\r\n");
    mqttClient.publish(&amp;In[0], "@guis BGC:#FFFFFF\r\n");
    delay(100);

    // initialize GUI
    mqttClient.publish(&amp;In[0], "|LB UID:title X:50 Y:20 FSZ:4 FFA:\"font8\" TXT:\"Resource&lt;br&gt;downloader\"\r\n");
    mqttClient.publish(&amp;In[0], "|VI UID:fire X:50 Y:50 W:70 VP:\"https://i.imgur.com/lVwrTnZ.mp4\"\r\n");
    mqttClient.publish(&amp;In[0], "|IM UID:play X:30 Y:70 W:15 IP:\"https://i.imgur.com/Gs2ERbO.png\"\r\n");
    mqttClient.publish(&amp;In[0], "|IM UID:pause X:70 Y:70 W:15 IP:\"https://i.imgur.com/FXywHFH.png\"\r\n");
    mqttClient.publish(&amp;In[0], "|LB UID:details X:50 Y:90 FSZ:2 TXT:\"GUI-O resource downloader&lt;br&gt;demonstration by kl3m3n\"\r\n");
  }
  else if(msg.startsWith("@play")) {
    mqttClient.publish(&amp;In[0], "@fire PLS:1\r\n");
  }
  else if(msg.startsWith("@pause")) {
    mqttClient.publish(&amp;In[0], "@fire PLS:2\r\n");    
  }
}
</code></pre>
<h3>3. ESTABLISH CONNECTION</h3>
<p dir="auto">Make sure that the GUI-O application is connected to the MQTT server.<br />
Also make sure that the ESP32 board (or other Arduino supported board) is connected to the MQTT server (you can check this by observing the serial debug messages using the Arduino serial monitor).</p>
<p dir="auto"><strong>NOTE:</strong> make sure that you are connected to WiFi as the GUI-O app will require connection in order to download the resources. If mobile data connection is used, please open the settings menu and enable data usage from "General settings -&gt; Network usage -&gt; Use any network". The resources will be downloaded only once; after that, the resources will be loaded from local storage.</p>
<p dir="auto">Press the <strong>Initialize</strong> button (see image below) from the GUI-O application home screen.</p>
<p dir="auto"><img src="https://i.imgur.com/DDEHAR7l.jpg" alt="initialize_button.jpg" class=" img-fluid img-markdown" /></p>
<h3>4. THE RESULT</h3>
<p dir="auto">Image below shows the result (screen capture) on my Android device after pressing the "Initialize" button. The video playback state can be controlled with the "play" and "pause" buttons. Note that the buttons are also images downloaded from online resource.</p>
<p dir="auto"><img src="https://i.imgur.com/MzdoVyXl.jpg" alt="screen.jpg" class=" img-fluid img-markdown" /></p>
<hr />
<p dir="auto">If you have any questions or run into any problems, please let me know!</p>
<p dir="auto">Best regards,<br />
kl3m3n</p>
]]></description><link>https://forum.gui-o.com/topic/89/episode-4-resource-downloader</link><guid isPermaLink="true">https://forum.gui-o.com/topic/89/episode-4-resource-downloader</guid><dc:creator><![CDATA[kl3m3n]]></dc:creator><pubDate>Sat, 12 Nov 2022 09:59:14 GMT</pubDate></item><item><title><![CDATA[Episode 3: NFC reader]]></title><description><![CDATA[<p dir="auto">I will be using Android builtin NFC reader to read text records of NFC tags. The text records will be displayed in a scroll-able text widget.</p>
<p dir="auto"><strong>I will be using GUI-O Bluetooth SPP connection, but the example can be easily be ported to other connection types.</strong></p>
<p dir="auto"><strong>Software prerequisites:</strong></p>
<ul>
<li>
<p dir="auto">Arduino IDE (<a href="https://www.arduino.cc/en/software" rel="nofollow ugc">https://www.arduino.cc/en/software</a>)</p>
</li>
<li>
<p dir="auto">ESP32 Arduino board support, if using ESP32 based board (see <a href="https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html" rel="nofollow ugc">https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html</a>)</p>
</li>
<li>
<p dir="auto">GUI-O design tool (<a href="https://www.gui-o.com/design-tool" rel="nofollow ugc">https://www.gui-o.com/design-tool</a>)</p>
</li>
<li>
<p dir="auto">GUI-O application (<a href="https://play.google.com/store/apps/details?id=com.guio.guioapp" rel="nofollow ugc">https://play.google.com/store/apps/details?id=com.guio.guioapp</a>)</p>
</li>
<li>
<p dir="auto">For additional information about the GUI-O application, download the developer manual from <a href="https://www.gui-o.com/" rel="nofollow ugc">https://www.gui-o.com/</a></p>
</li>
</ul>
<p dir="auto"><strong>Components needed:</strong></p>
<ul>
<li>ESP32-WROOM-32 (or any other Arduino supported Bluetooth capable board)</li>
</ul>
<p dir="auto"><strong>The entire tutorial is split into various steps. All necessary information is given in each step</strong>.</p>
<h3>0. DESIGN THE GUI (optional)</h3>
<p dir="auto">The best way to create a GUI layout is to use GUI-O live designer tool.</p>
<p dir="auto">Note that the Arduino source code already includes the necessary commands, so this step is not needed, unless you want to make some visual adjustments. If you make adjustments, please include the generated ASCII code in the Arduino source code (see section 1. UPLOAD THE SOURCE CODE).</p>
<p dir="auto">First, you need to establish a TCP/IP connection between the designer tool and GUI-O application:</p>
<ol>
<li>Determine the local IP address of your PC's network interface (WiFi or Ethernet)</li>
</ol>
<ul>
<li>Under Windows, open the command prompt, enter <code>ipconfig</code> and press Enter</li>
<li>Under Linux, open the terminal, enter <code>ifconfig</code> and press Enter</li>
</ul>
<ol start="2">
<li>
<p dir="auto">Open GUI-O application and open settings menu. Select "Connections -&gt; Ethernet" and create a new device with IP address (determined from 1.) and any port between 49152 - 65535</p>
</li>
<li>
<p dir="auto">Open GUI-O designer and select "TCP/IP connection" tab. Set the IP address and port. Both values must match the device settings created within the GUI-O application. Click "Start server" button.</p>
</li>
<li>
<p dir="auto">Within the GUI-O application, tap the created device and wait for successful connection.</p>
</li>
<li>
<p dir="auto">In the GUI-O designer, select "File -&gt; Load designer file" and load the <a href="https://drive.google.com/uc?export=download&amp;id=18IP5UB10tWy5Gb9m5-8P7D_HyIDq1Aq1" rel="nofollow ugc">NfcReader.gdf</a> design file. Make the desired adjustments, if necessary. Copy / replace the GUI-O commands into the Arduino source code (see section 1. UPLOAD THE SOURCE CODE).</p>
</li>
</ol>
<h3>1. UPLOAD THE SOURCE CODE</h3>
<p dir="auto">The source code has inline comments, describing the important parts of the code. You can copy the source code from the snippet below, or download it <a href="https://drive.google.com/uc?export=download&amp;id=1wH6sucq9ocdqW2rLVZr-noS822xTeL3O" rel="nofollow ugc">here</a>.</p>
<p dir="auto">Upload the code to your board (make sure that the correct board and upload port are selected). Reset the board after upload.</p>
<pre><code>/*
 * GUI-O NFC reader Bluetooth example (using ESP32-WROOM-32)
 *
 * Copyright (C) 2022, kl3m3n
 * last updated on 5.11.2022
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include "BluetoothSerial.h"

// if not enabled, the SDK must be recompiled
#if !defined(CONFIG_BT_ENABLED) || !defined(CONFIG_BLUEDROID_ENABLED)
#error Bluetooth is not enabled! Please run `make menuconfig` to and enable it
#endif

// forward declare parser for incoming messages
void parseGuioMsg(const String &amp;msg);

// icoming data buffer
String in;

// global
BluetoothSerial btSerial;

void setup() {
  // debug output
  Serial.begin(115200);
  
  // setup bluetooth serial
  btSerial.begin("NFCReaderBluetooth");
  
  Serial.println("Bluetooth ready to pair!");
}

void loop() {
  while(btSerial.available()) {
    const char c = btSerial.read();
    in += c;
  
    if(c == '\n') {
      // parse message string
      parseGuioMsg(in);
      // clear buffer
      in = "";
    }  
  }
}

void sendMsg(const String &amp;msg) {
  btSerial.write((const uint8_t*) msg.c_str(), msg.length());
}

void parseGuioMsg(const String &amp;msg) {
  if(msg.startsWith("@init")) {
    Serial.println("GUI-O app is requesting INITIALIZATION!");

    // clear screen, hardware and set background
    sendMsg("@cls\r\n");
    sendMsg("@clh\r\n");
    sendMsg("@guis BGC:#FFFFFF\r\n");
    delay(100);

    // initialize GUI
    sendMsg("|LB UID:title X:50 Y:20 FSZ:4 FFA:\"font8\" TXT:\"NFC&lt;br&gt;reader\"\r\n");
    sendMsg("|TA UID:nfcOutput X:50 Y:50 W:70 H:40 FSZ:2 FGC:#FFFFFF\r\n");
    sendMsg("|LB UID:details X:50 Y:90 FSZ:2 TXT:\"GUI-O NFC reader&lt;br&gt;demonstration by kl3m3n\"\r\n");
    // initialize NFC hardware
    sendMsg("|NFC UID:nfc HID:nfc SEN:1\r\n");
  }
  else if(msg.startsWith("@nfc")) {
    const auto idx = msg.indexOf(' ');
    if(idx &gt; 0) {
      String txt = msg.substring(idx + 1); txt.trim();
      // display NFC (text) record
      sendMsg("@nfcOutput TXT:\"" + txt + "\"\r\n");
    }
  }
}
</code></pre>
<h3>2. ESTABLISH CONNECTION</h3>
<p dir="auto">Make sure that the ESP32 board is ready for pairing (you can check this by observing the serial debug messages using the Arduino serial monitor).</p>
<p dir="auto">Open GUI-O application and navigate to settings menu. Select "Connections -&gt; Bluetooth and IoT" and search for devices (enable Bluetooth and Location services, if prompted). Tap on the "NFCReaderBluetooth" device and wait for successful connection (confirm device pairing if prompted).</p>
<p dir="auto">Close the settings menu and press the <strong>Initialize</strong> button (see image below) from the GUI-O application home screen.</p>
<p dir="auto"><img src="https://i.imgur.com/DDEHAR7l.jpg" alt="initialize_button.jpg" class=" img-fluid img-markdown" /></p>
<h3>3. THE RESULT</h3>
<p dir="auto">Image below shows the result (screen capture) on my Android device after pressing the "Initialize" button and scanning two different NFC tags (I added some arbitrary text records using a third-party application).</p>
<p dir="auto">Note that if code "-2" is displayed after pressing the "Initialize" button, the NFC is available, but is not enabled. In this case you should enable NFC through Android system settings. If code "-1" is displayed, your device does not support NFC.</p>
<p dir="auto"><img src="https://i.imgur.com/92XY6rbl.jpg" alt="screen.jpg" class=" img-fluid img-markdown" /></p>
<hr />
<p dir="auto">If you have any questions or run into any problems, please let me know!</p>
<p dir="auto">Best regards,<br />
kl3m3n</p>
]]></description><link>https://forum.gui-o.com/topic/88/episode-3-nfc-reader</link><guid isPermaLink="true">https://forum.gui-o.com/topic/88/episode-3-nfc-reader</guid><dc:creator><![CDATA[kl3m3n]]></dc:creator><pubDate>Sat, 05 Nov 2022 10:43:59 GMT</pubDate></item><item><title><![CDATA[Episode 2: RGB LED control]]></title><description><![CDATA[<p dir="auto">I will be using a RGB LED to create various color combinations using three simple / basic slider widgets. The sliders will control each channel separately (red, green and blue) by setting their values between 0-255 through user input.</p>
<p dir="auto"><strong>I will be using GUI-O IoT (MQTT) connection, but the example can be easily be ported to other connection types.</strong></p>
<p dir="auto"><strong>Software prerequisites:</strong></p>
<ul>
<li>
<p dir="auto">Arduino IDE (<a href="https://www.arduino.cc/en/software" rel="nofollow ugc">https://www.arduino.cc/en/software</a>)</p>
</li>
<li>
<p dir="auto">ESP32 Arduino board support, if using ESP32 based board (see <a href="https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html" rel="nofollow ugc">https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html</a>)</p>
</li>
<li>
<p dir="auto">Arduino Client for MQTT(<a href="https://github.com/knolleary/pubsubclient" rel="nofollow ugc">https://github.com/knolleary/pubsubclient</a>)<br />
You can follow the setup instructions or directly download and include the <strong><a href="https://drive.google.com/uc?export=download&amp;id=1yRJCDFR2xQDodyIA_lqKfcYdU6pAFy1C" rel="nofollow ugc">PubSubClient.zip</a></strong> library within the Arduino IDE (Sketch -&gt; Include Library -&gt; Add .ZIP library)</p>
</li>
<li>
<p dir="auto">GUI-O design tool (<a href="https://www.gui-o.com/design-tool" rel="nofollow ugc">https://www.gui-o.com/design-tool</a>)</p>
</li>
<li>
<p dir="auto">GUI-O application (<a href="https://play.google.com/store/apps/details?id=com.guio.guioapp" rel="nofollow ugc">https://play.google.com/store/apps/details?id=com.guio.guioapp</a>)</p>
</li>
<li>
<p dir="auto">For additional information about the GUI-O application, download the developer manual from <a href="https://www.gui-o.com/" rel="nofollow ugc">https://www.gui-o.com/</a></p>
</li>
</ul>
<p dir="auto"><strong>Components needed:</strong></p>
<ul>
<li>ESP32-WROOM-32 (or any other Arduino supported WiFi capable board; see <a href="https://github.com/knolleary/pubsubclient#compatible-hardware" rel="nofollow ugc">https://github.com/knolleary/pubsubclient#compatible-hardware</a> for compatible hardware)</li>
<li>3x 220Ω resistor</li>
<li>RGB LED (common anode)</li>
</ul>
<p dir="auto"><strong>The entire tutorial is split into various steps. All necessary information is given in each step</strong>.</p>
<h3>0. DESIGN THE GUI (optional)</h3>
<p dir="auto">The best way to create a GUI layout is to use GUI-O live designer tool.</p>
<p dir="auto">Note that the Arduino source code already includes the necessary commands, so this step is not needed, unless you want to make some visual adjustments. If you make adjustments, please include the generated ASCII code in the Arduino source code (see section 3. MODIFY AND UPLOAD THE SOURCE CODE).</p>
<p dir="auto">First, you need to establish a TCP/IP connection between the designer tool and GUI-O application:</p>
<ol>
<li>Determine the local IP address of your PC's network interface (WiFi or Ethernet)</li>
</ol>
<ul>
<li>Under Windows, open the command prompt, enter <code>ipconfig</code> and press Enter</li>
<li>Under Linux, open the terminal, enter <code>ifconfig</code> and press Enter</li>
</ul>
<ol start="2">
<li>
<p dir="auto">Open GUI-O application and open settings menu. Select "Connections -&gt; Ethernet" and create a new device with IP address (determined from 1.) and any port between 49152 - 65535</p>
</li>
<li>
<p dir="auto">Open GUI-O designer and select "TCP/IP connection" tab. Set the IP address and port. Both values must match the device settings created within the GUI-O application. Click "Start server" button.</p>
</li>
<li>
<p dir="auto">Within the GUI-O application, tap the created device and wait for successful connection.</p>
</li>
<li>
<p dir="auto">In the GUI-O designer, select "File -&gt; Load designer file" and load the <a href="https://drive.google.com/uc?export=download&amp;id=1FnPEhPcqejmpqkJ3zKdlsmjTItIA5KBL" rel="nofollow ugc">RgbLedControl.gdf</a> design file. Make the desired adjustments, if necessary. Copy / replace the GUI-O commands into the Arduino source code (see section 3. MODIFY AND UPLOAD THE SOURCE CODE).</p>
</li>
</ol>
<h3>1.  CONNECT THE COMPONENTS</h3>
<p dir="auto">Connecting the components is straightforward. "D25", "D33" and "D32" are GPIO pins that are capable of producing PWM output. The values of the current limiting resistors are not optimal, but in my case, the LED is still bright enough.</p>
<p dir="auto"><img src="https://i.imgur.com/vmHt9dsl.png" alt="schematic.png" class=" img-fluid img-markdown" /></p>
<h3>2. CREATE A UNIQUE MQTT CHANNEL</h3>
<p dir="auto">Open GUI-O application and navigate to settings menu. Select "Connections -&gt; IoT" and add a new device. After adding the device, note the <strong>In</strong> and <strong>Out</strong> token (you can share this tokens e.g., to your e-mail by pressing the "share" button).</p>
<p dir="auto">Finally, press "Connect" menu entry to establish the connection with the MQTT server.</p>
<h3>3. MODIFY AND UPLOAD THE SOURCE CODE</h3>
<p dir="auto">The source code has inline comments, describing the important parts of the code. You can copy the source code from the snippet below, or download it <a href="https://drive.google.com/uc?export=download&amp;id=14MLY8YIhnns9OjfoWIwnbcfOxEYblkL5" rel="nofollow ugc">here</a>.</p>
<p dir="auto">The only thing that needs to be done is to set the <strong>ssid</strong> and <strong>password</strong> of your router and the unique <strong>In</strong> and <strong>Out</strong> channels that were generated by the GUI-O application (see section 2. CREATE A UNIQUE MQTT CHANNEL).</p>
<p dir="auto">After setting these values, upload the code to your board (make sure that the correct board and upload port are selected). Reset the board after upload.</p>
<pre><code>/*
 * GUI-O Rgb control MQTT example (using ESP32-WROOM-32)
 *
 * Copyright (C) 2022, kl3m3n
 * last updated on 4.11.2022
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include &lt;WiFi.h&gt;
#include &lt;PubSubClient.h&gt;

static const char *ssid = "&lt;ssid&gt;"; // router name
static const char *pass = "&lt;pass&gt;"; // router password

static const char *mqttServer = "mqtt.gui-o.com";   // host name
static const char *mqttUser = "gui-o-mqtt-generic"; // user name
static const char *mqttPass = "lqXeZpv5VJyv0XBT";   // password

// IMPORTANT NOTE: if optional user name was specified when adding a new IoT device,
// the user name should also be included when setting the topics (e.g., "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/&lt;user_name&gt;")
static const char *Out = "&lt;Out&gt;"; // GUI-O app publish topic
static const char *In = "&lt;In&gt;";  // GUI-O app subscribe topic

// mqtt client
WiFiClient wiFiClient;
PubSubClient mqttClient(wiFiClient);

// forward declare functions for mqtt messages handling
void mqttCallback(char* topic, byte* message, unsigned int length);
void parseGuioMsg(const String &amp;msg);

// LED setup
namespace led {
  static const uint8_t R_PIN = 25;
  static const uint8_t G_PIN = 33;
  static const uint8_t B_PIN = 32;
  //
  static const uint8_t R_CHANNEL = 0;
  static const uint8_t G_CHANNEL = 1;
  static const uint8_t B_CHANNEL = 2;
  //
  static const double LED_FREQ = 5000.0;
  static const uint8_t LED_BITS = 8;
} // namespace led

// LED rgb values
uint8_t redValue = 0;
uint8_t greenValue = 0;
uint8_t blueValue = 0;

void setup() {
  // debug output
  Serial.begin(115200);

  // setup LED
  ledcSetup(led::R_CHANNEL, led::LED_FREQ, led::LED_BITS);
  ledcSetup(led::G_CHANNEL, led::LED_FREQ, led::LED_BITS);
  ledcSetup(led::B_CHANNEL, led::LED_FREQ, led::LED_BITS);
  // attach the channels to the GPIOs
  ledcAttachPin(led::R_PIN, led::R_CHANNEL);
  ledcAttachPin(led::G_PIN, led::G_CHANNEL);
  ledcAttachPin(led::B_PIN, led::B_CHANNEL);
  // set initial values ("inverted" logic - see schematic)
  delay(100);
  ledcWrite(led::R_CHANNEL, 255 - redValue);
  ledcWrite(led::G_CHANNEL, 255 - greenValue);
  ledcWrite(led::B_CHANNEL, 255 - blueValue);
  
  // connect WiFi (keep trying...)
  Serial.print("Connecting to ");
  Serial.println(ssid);
  
  WiFi.begin(ssid, pass);
  while(WiFi.status() != WL_CONNECTED) { 
    Serial.print(".");
    delay(500); 
  }
  
  Serial.println("WiFi connected!"); 
  
  // setup mqtt
  mqttClient.setServer(mqttServer, 1883);
  mqttClient.setCallback(mqttCallback);
}

void loop() {
  while(!mqttClient.connected()) {
    Serial.println("MQTT connecting...");

    // mqtt client id is the mac address (AABBCCDDEEFF)
    char mqttClientId[15];    
    uint8_t mac[6];
    WiFi.macAddress(mac);

    snprintf(mqttClientId, sizeof(mqttClientId), "%02x%02x%02x%02x%02x%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);

    if(mqttClient.connect(mqttClientId, mqttUser, mqttPass)) {
      Serial.println("MQTT connected!");
      mqttClient.subscribe(&amp;Out[0]);
    }
    else {
      Serial.print("MQTT connection failed (");
      Serial.print(mqttClient.state());
      Serial.println(")! Retrying...");      
      delay(2500);
    }
  }
  mqttClient.loop();
}

// mqtt callback function
void mqttCallback(char* topic, byte* message, unsigned int length) {
  // build message string
  String msg;
  for(int i = 0; i &lt; length; i++) {
    msg += (char) message[i];
  }
  // parse message string
  parseGuioMsg(msg);
}

void parseGuioMsg(const String &amp;msg) {
  // lambda for LED value extraction
  auto ledValue = [](const String &amp;msg) -&gt; uint8_t {
    uint8_t value = 0;    
    const int idx = msg.indexOf(' ');
    if(idx &gt; 0) {
      value = constrain(msg.substring(idx + 1).toInt(), 0, 255);
      value = (255 - value); // "inverted" logic - see schematic
    }
    return value;
  };
  
  if(msg.startsWith("@init")) {
    Serial.println("GUI-O app is requesting INITIALIZATION!");

    // clear screen and set background
    mqttClient.publish(&amp;In[0], "@cls\r\n");
    mqttClient.publish(&amp;In[0], "@guis BGC:#FFFFFF\r\n");
    delay(100);

    // initialize GUI
    mqttClient.publish(&amp;In[0], "|LB UID:title X:50 Y:20 FSZ:4 FFA:\"font8\" TXT:\"RGB LED&lt;br&gt;control\"\r\n");
    mqttClient.publish(&amp;In[0], "|SL UID:red X:30 Y:50 H:1 ROT:270 FGC:#FF0000 SFGC:#FF0000 HAW:7 HAH:7 HAR:3.5 HAC:#FF0000 IP:\"\" HVAL:255 RAD:0.5\r\n");
    mqttClient.publish(&amp;In[0], "|SL UID:green X:50 Y:50 H:1 ROT:270 FGC:#00FF00 SFGC:#00FF00 HAW:7 HAH:7 HAR:3.5 HAC:#00FF00 IP:\"\" HVAL:255 RAD:0.5\r\n");
    mqttClient.publish(&amp;In[0], "|SL UID:blue X:70 Y:50 H:1 ROT:270 FGC:#0000FF SFGC:#0000FF HAW:7 HAH:7 HAR:3.5 HAC:#0000FF IP:\"\" HVAL:255 RAD:0.5\r\n");
    mqttClient.publish(&amp;In[0], "|LB UID:details X:50 Y:90 FSZ:2 TXT:\"GUI-O RGB LED control&lt;br&gt;demonstration by kl3m3n\"\r\n");    
  }
  else if(msg.startsWith("@red")) {
    redValue = ledValue(msg);
    ledcWrite(led::R_CHANNEL, redValue);
  }
  else if(msg.startsWith("@green")) {
    greenValue = ledValue(msg);
    ledcWrite(led::G_CHANNEL, greenValue);
  }
  else if(msg.startsWith("@blue")) {
    blueValue = ledValue(msg);
    ledcWrite(led::B_CHANNEL, blueValue);
  }  
}
</code></pre>
<h3>4. ESTABLISH CONNECTION</h3>
<p dir="auto">Make sure that the GUI-O application is connected to the MQTT server.<br />
Also make sure that the ESP32 board (or other Arduino supported board) is connected to the MQTT server (you can check this by observing the serial debug messages using the Arduino serial monitor).</p>
<p dir="auto">Press the <strong>Initialize</strong> button (see image below) from the GUI-O application home screen.</p>
<p dir="auto"><img src="https://i.imgur.com/DDEHAR7l.jpg" alt="initialize_button.jpg" class=" img-fluid img-markdown" /></p>
<h3>5. THE RESULT</h3>
<p dir="auto">Image below shows the result (screen capture) on my Android device after pressing the "Initialize" button. The sliders control each LED channel through user input.</p>
<p dir="auto"><img src="https://i.imgur.com/jOZFfjgl.jpg" alt="screen.jpg" class=" img-fluid img-markdown" /></p>
<hr />
<p dir="auto">If you have any questions or run into any problems, please let me know!</p>
<p dir="auto">Best regards,<br />
kl3m3n</p>
]]></description><link>https://forum.gui-o.com/topic/87/episode-2-rgb-led-control</link><guid isPermaLink="true">https://forum.gui-o.com/topic/87/episode-2-rgb-led-control</guid><dc:creator><![CDATA[kl3m3n]]></dc:creator><pubDate>Fri, 04 Nov 2022 18:24:06 GMT</pubDate></item><item><title><![CDATA[Episode 1: Temperature reader]]></title><description><![CDATA[<p dir="auto">I will be using a thermistor to read and display the ambient temperature. The display will show the current ambient temperature and ambient temperature over time using a graphical representation.</p>
<p dir="auto"><strong>I will be using GUI-O IoT (MQTT) connection, but the example can be easily be ported to other connection types.</strong></p>
<p dir="auto"><strong>Software prerequisites:</strong></p>
<ul>
<li>
<p dir="auto">Arduino IDE (<a href="https://www.arduino.cc/en/software" rel="nofollow ugc">https://www.arduino.cc/en/software</a>)</p>
</li>
<li>
<p dir="auto">ESP32 Arduino board support, if using ESP32 based board (see <a href="https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html" rel="nofollow ugc">https://docs.espressif.com/projects/arduino-esp32/en/latest/installing.html</a>)</p>
</li>
<li>
<p dir="auto">Arduino Client for MQTT(<a href="https://github.com/knolleary/pubsubclient" rel="nofollow ugc">https://github.com/knolleary/pubsubclient</a>)<br />
You can follow the setup instructions or directly download and include the <strong><a href="https://drive.google.com/uc?export=download&amp;id=1yRJCDFR2xQDodyIA_lqKfcYdU6pAFy1C" rel="nofollow ugc">PubSubClient.zip</a></strong> library within the Arduino IDE (Sketch -&gt; Include Library -&gt; Add .ZIP library)</p>
</li>
<li>
<p dir="auto">GUI-O design tool (<a href="https://www.gui-o.com/design-tool" rel="nofollow ugc">https://www.gui-o.com/design-tool</a>)</p>
</li>
<li>
<p dir="auto">GUI-O application (<a href="https://play.google.com/store/apps/details?id=com.guio.guioapp" rel="nofollow ugc">https://play.google.com/store/apps/details?id=com.guio.guioapp</a>)</p>
</li>
<li>
<p dir="auto">For additional information about the GUI-O application, download the developer manual from <a href="https://www.gui-o.com/" rel="nofollow ugc">https://www.gui-o.com/</a></p>
</li>
</ul>
<p dir="auto"><strong>Components needed:</strong></p>
<ul>
<li>ESP32-WROOM-32 (or any other Arduino supported WiFi capable board; see <a href="https://github.com/knolleary/pubsubclient#compatible-hardware" rel="nofollow ugc">https://github.com/knolleary/pubsubclient#compatible-hardware</a> for compatible hardware)</li>
<li>10k resistor</li>
<li>thermistor</li>
</ul>
<p dir="auto"><strong>The entire tutorial is split into various steps. All necessary information is given in each step</strong>.</p>
<h3>0. DESIGN THE GUI (optional)</h3>
<p dir="auto">The best way to create a GUI layout is to use GUI-O live designer tool.</p>
<p dir="auto">Note that the Arduino source code already includes the necessary commands, so this step is not needed, unless you want to make some visual adjustments. If you make adjustments, please include the generated ASCII code in the Arduino source code (see section 3. MODIFY AND UPLOAD THE SOURCE CODE).</p>
<p dir="auto">First, you need to establish a TCP/IP connection between the designer tool and GUI-O application:</p>
<ol>
<li>Determine the local IP address of your PC's network interface (WiFi or Ethernet)</li>
</ol>
<ul>
<li>Under Windows, open the command prompt, enter <code>ipconfig</code> and press Enter</li>
<li>Under Linux, open the terminal, enter <code>ifconfig</code> and press Enter</li>
</ul>
<ol start="2">
<li>
<p dir="auto">Open GUI-O application and open settings menu. Select "Connections -&gt; Ethernet" and create a new device with IP address (determined from 1.) and any port between 49152 - 65535</p>
</li>
<li>
<p dir="auto">Open GUI-O designer and select "TCP/IP connection" tab. Set the IP address and port. Both values must match the device settings created within the GUI-O application. Click "Start server" button.</p>
</li>
<li>
<p dir="auto">Within the GUI-O application, tap the created device and wait for successful connection.</p>
</li>
<li>
<p dir="auto">In the GUI-O designer, select "File -&gt; Load designer file" and load the <a href="https://drive.google.com/uc?export=download&amp;id=1SkPpmi1JSgxIaKRIh5xxIYygUXNpFm04" rel="nofollow ugc">TemperatureReader.gdf</a> design file. Make the desired adjustments, if necessary. Copy / replace the GUI-O commands into the Arduino source code (see section 3. MODIFY AND UPLOAD THE SOURCE CODE).</p>
</li>
</ol>
<h3>1.  CONNECT THE COMPONENTS</h3>
<p dir="auto">Connecting the components is straightforward. The "D35" is one of the ADC1 pins on ESP32 (note that ADC2 pins are not available when WiFi is enabled).</p>
<p dir="auto"><img src="https://i.imgur.com/yof1CLUm.png" alt="schematic.png" class=" img-fluid img-markdown" /></p>
<h3>2. CREATE A UNIQUE MQTT CHANNEL</h3>
<p dir="auto">Open GUI-O application and navigate to settings menu. Select "Connections -&gt; IoT" and add a new device. After adding the device, note the <strong>In</strong> and <strong>Out</strong> token (you can share this tokens e.g., to your e-mail by pressing the "share" button).</p>
<p dir="auto">Finally, press "Connect" menu entry to establish the connection with the MQTT server.</p>
<h3>3. MODIFY AND UPLOAD THE SOURCE CODE</h3>
<p dir="auto">The source code has inline comments, describing the important parts of the code. You can copy the source code from the snippet below, or download it <a href="https://drive.google.com/uc?export=download&amp;id=1mkuLbigmnttXy3WSF5JgrOPpkCNuOTTE" rel="nofollow ugc">here</a>.</p>
<p dir="auto">The only thing that needs to be done is to set the <strong>ssid</strong> and <strong>password</strong> of your router and the unique <strong>In</strong> and <strong>Out</strong> channels that were generated by the GUI-O application (see section 2. CREATE A UNIQUE MQTT CHANNEL).</p>
<p dir="auto">After setting these values, upload the code to your board (make sure that the correct board and upload port are selected). Reset the board after upload.</p>
<pre><code>/*
 * GUI-O Thermistor MQTT example (using ESP32-WROOM-32)
 *
 * Copyright (C) 2022, kl3m3n
 * last updated on 30.10.2022
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include &lt;WiFi.h&gt;
#include &lt;PubSubClient.h&gt;

static const char *ssid = "&lt;ssid&gt;"; // router name
static const char *pass = "&lt;pass&gt;"; // router password

static const char *mqttServer = "mqtt.gui-o.com";   // host name
static const char *mqttUser = "gui-o-mqtt-generic"; // user name
static const char *mqttPass = "lqXeZpv5VJyv0XBT";   // password

// IMPORTANT NOTE: if optional user name was specified when adding a new IoT device,
// the user name should also be included when setting the topics (e.g., "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/&lt;user_name&gt;")
static const char *Out = "&lt;Out&gt;"; // GUI-O app publish topic
static const char *In = "&lt;In&gt;";  // GUI-O app subscribe topic

// mqtt client
WiFiClient wiFiClient;
PubSubClient mqttClient(wiFiClient);

// forward declare functions for mqtt messages handling
void mqttCallback(char* topic, byte* message, unsigned int length);
void parseGuioMsg(const String &amp;msg);

// setup thermistor read settings
char buf[100];
const int thermistorPin = 35;
unsigned long startTimestampMsec, currentTimestampMsec;
const unsigned long readIntervalMsec = 500; // milliseconds

void setup() {
  // debug output
  Serial.begin(115200);
  
  // connect WiFi (keep trying...)
  Serial.print("Connecting to ");
  Serial.println(ssid);
  
  WiFi.begin(ssid, pass);
  while(WiFi.status() != WL_CONNECTED) { 
    Serial.print(".");
    delay(500); 
  }
  
  Serial.println("WiFi connected!"); 
  
  // setup mqtt
  mqttClient.setServer(mqttServer, 1883);
  mqttClient.setCallback(mqttCallback);

  startTimestampMsec = millis();
}

void loop() {
  while(!mqttClient.connected()) {
    Serial.println("MQTT connecting...");

    // mqtt client id is the mac address (AABBCCDDEEFF)
    char mqttClientId[15];    
    uint8_t mac[6];
    WiFi.macAddress(mac);

    snprintf(mqttClientId, sizeof(mqttClientId), "%02x%02x%02x%02x%02x%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);

    if(mqttClient.connect(mqttClientId, mqttUser, mqttPass)) {
      Serial.println("MQTT connected!");
      mqttClient.subscribe(&amp;Out[0]);
    }
    else {
      Serial.print("MQTT connection failed (");
      Serial.print(mqttClient.state());
      Serial.println(")! Retrying...");      
      delay(2500);
    }
  }
  mqttClient.loop();

  // get and display temperature 
  currentTimestampMsec = millis();
  
  if(currentTimestampMsec - startTimestampMsec &gt; readIntervalMsec) {
    // read adc
    const int adcValue = analogRead(thermistorPin);
    // calculate voltage
    const float voltage = adcValue * 3.3 / 4096.0;
    // calculate resistance (voltage divider equation)
    const float resistance = 10.0 * voltage / (3.3 - voltage);
    // calculate temperature using thermistor equation
    // using thermistor with thermal index = 3950, nominal resistance = 10k
    float temp = 1.0 / (log(resistance / 10.0) / 3950 + 1.0 / (273.15 + 25.0));
    temp -= 273.15;

    // label
    snprintf(buf, sizeof(buf), "@temp TXT:\"%.2f °C\"\r\n", temp);
    mqttClient.publish(&amp;In[0], &amp;buf[0]);
    // chart
    snprintf(buf, sizeof(buf), "@tempCh PLI:\"id0\" PLC:\"#4C4C4C\" YP:\"%.1f\"\r\n", temp);
    mqttClient.publish(&amp;In[0], &amp;buf[0]);
    
    Serial.print("T = ");
    Serial.print(temp);
    Serial.println(" °C");

    // reset read interval
    startTimestampMsec = millis();
  }
}

// mqtt callback function
void mqttCallback(char* topic, byte* message, unsigned int length) {
  // build message string
  String msg;
  for(int i = 0; i &lt; length; i++) {
    msg += (char) message[i];
  }
  // parse message string
  parseGuioMsg(msg);
}

void parseGuioMsg(const String &amp;msg) {
  if(msg.startsWith("@init")) {
    Serial.println("GUI-O app is requesting INITIALIZATION!");

    // clear screen and set background
    mqttClient.publish(&amp;In[0], "@cls\r\n");
    mqttClient.publish(&amp;In[0], "@guis BGC:#FFFFFF\r\n");
    delay(100);

    // initialize GUI
    mqttClient.publish(&amp;In[0], "|LB UID:title X:50 Y:20 FSZ:4 FFA:\"font8\" TXT:\"Temperature&lt;br&gt;reader\"\r\n");
    mqttClient.publish(&amp;In[0], "|BSR UID:container X:50 Y:40 W:30 H:5 RAD:1 BTH:0\r\n");
    mqttClient.publish(&amp;In[0], "|LB UID:temp X:50 Y:40 FGC:#FFFFFF TXT:\"n/a\"\r\n");
    mqttClient.publish(&amp;In[0], "|CH UID:tempCh X:50 Y:65 YLO:15 YHI:35\r\n");
    mqttClient.publish(&amp;In[0], "|LB UID:details X:50 Y:90 FSZ:2 TXT:\"GUI-O temperature reader&lt;br&gt;demonstration by kl3m3n\"\r\n");
  }  
}
</code></pre>
<h3>4. ESTABLISH CONNECTION</h3>
<p dir="auto">Make sure that the GUI-O application is connected to the MQTT server.<br />
Also make sure that the ESP32 board (or other Arduino supported board) is connected to the MQTT server (you can check this by observing the serial debug messages using the Arduino serial monitor).</p>
<p dir="auto">Press the <strong>Initialize</strong> button (see image below) from the GUI-O application home screen.</p>
<p dir="auto"><img src="https://i.imgur.com/DDEHAR7l.jpg" alt="initialize_button.jpg" class=" img-fluid img-markdown" /></p>
<h3>5. THE RESULT</h3>
<p dir="auto">Image below shows the result (screen capture) on my Android device after pressing the "Initialize" button. The label and chart are updated every time the ESP32 board calculates the temperature and publishes new data to the MQTT server.</p>
<p dir="auto"><img src="https://i.imgur.com/a24uN0tl.jpg" alt="screen.jpg" class=" img-fluid img-markdown" /></p>
<hr />
<p dir="auto">If you have any questions or run into any problems, please let me know!</p>
<p dir="auto">Best regards,<br />
kl3m3n</p>
]]></description><link>https://forum.gui-o.com/topic/86/episode-1-temperature-reader</link><guid isPermaLink="true">https://forum.gui-o.com/topic/86/episode-1-temperature-reader</guid><dc:creator><![CDATA[kl3m3n]]></dc:creator><pubDate>Mon, 31 Oct 2022 14:48:34 GMT</pubDate></item><item><title><![CDATA[Introduction]]></title><description><![CDATA[<p dir="auto">This category aims to show (through practical examples), how <strong>GUI-O</strong> can be used as a display in various embedded projects.</p>
<p dir="auto"><strong>GUI-O</strong> is an Android application that lets you quickly create professional graphical user interfaces (GUIs) for controlling any device using ASCII text based commands. It also enables simple interaction with various hardware of the Android device (NFC, GPS, camera, etc.).</p>
<p dir="auto">In this series, I will mostly be using ESP32-WROOM-32 development board, which can be used for all connection types that <strong>GUI-O</strong> supports:</p>
<ol>
<li>Bluetooth SPP</li>
<li>Bluetooth LE (NUS or custom)</li>
<li>IoT (MQTT)</li>
<li>USB</li>
<li>Ethernet (TCP/IP)</li>
</ol>
<p dir="auto">Of course, you are not limited to this particular board... Any device that supports any of the listed connection types can be used (e.g., Raspberry boards, Arduino boards, STM boards, ESP32, ESP8266, HC (HM) modules, PC, etc.).</p>
<p dir="auto">Note that GUI-O app DEMO version allows creating up to 6 widgets and can only interact with NFC, RTC (real-time clock) and GPS.<br />
PRO version has no limitations. For more information, see <a href="http://www.gui-o.com" rel="nofollow ugc">www.gui-o.com</a>.</p>
<hr />
<p dir="auto">My name is Klemen (kl3m3n) and I am the developer of the <strong>GUI-O application</strong> (<a href="http://www.gui-o.com" rel="nofollow ugc">www.gui-o.com</a>) and <strong>GUI-O designer tool</strong> (<a href="https://www.gui-o.com/design-tool" rel="nofollow ugc">https://www.gui-o.com/design-tool</a>).</p>
<p dir="auto">Let's dive in...</p>
<hr />
<p dir="auto">Just for reference, the following widgets are available. All widgets are highly customizable. Widgets can be positioned on up to five (virtual) screens.</p>
<p dir="auto"><img src="https://i.imgur.com/pCuLrCbl.png" alt="widgets.png" class=" img-fluid img-markdown" /></p>
<p dir="auto">Additionally, interaction with the following hardware is available (if supported by the device):</p>
<ul>
<li>NFC (Near-field communication)</li>
<li>Audio player</li>
<li>Tone player</li>
<li>Real-time clock (RTC)</li>
<li>Position sensor (GPS)</li>
<li>Vibrator</li>
<li>Camera capture</li>
<li>File I/O</li>
<li>Screen orientation</li>
<li>Battery status</li>
<li>Brightness setting</li>
<li>Device sensors:
<ul>
<li>Accelerometer</li>
<li>Altimeter</li>
<li>Ambient light sensor</li>
<li>Ambient temperature sensor</li>
<li>Compass</li>
<li>Distance sensor</li>
<li>Gyroscope</li>
<li>Holster sensor</li>
<li>Humidity sensor</li>
<li>IR Proximity sensor</li>
<li>Lid sensor</li>
<li>Light sensor</li>
<li>Magnetometer</li>
<li>Orientation sensor</li>
<li>Pressure sensor</li>
<li>Proximity sensor</li>
<li>Rotation sensor</li>
<li>Tap sensor</li>
<li>Tilt sensor</li>
</ul>
</li>
</ul>
]]></description><link>https://forum.gui-o.com/topic/85/introduction</link><guid isPermaLink="true">https://forum.gui-o.com/topic/85/introduction</guid><dc:creator><![CDATA[kl3m3n]]></dc:creator><pubDate>Mon, 31 Oct 2022 08:56:49 GMT</pubDate></item></channel></rss>