<?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[Lesson 13.1. UI. Full manual]]></title><description><![CDATA[<h2>The purpose of this lesson</h2>
<p dir="auto">Hi! Today we will get acquainted with such a tempting thing as the M5 UI. This is a library designed to create a user interface. Thanks to M5 UI you can connect all kinds of fields, buttons, sliders and switches with a couple of lines of code, create conditional layers. Although the process of connecting UI elements is very simple, you can also use the visual M5 UI Designer for Arduino IDE tool.</p>
<p dir="auto"><img src="https://pp.userapi.com/c844417/v844417774/bc2fe/ce7ZV52JvGY.jpg" alt="" class=" img-fluid img-markdown" /></p>
<p dir="auto">Figure 1</p>
<p dir="auto">It is necessary to consider all the existing elements of the library M5 UI in practice, as well as get acquainted with the process of creating the interface in the application M5 UI Designer.</p>
<h2>Short help</h2>
<p dir="auto">A graphical interface is a set of functional elements that are required for interaction with the user. As these elements appear in various fields of the input/output of text, buttons, checkboxes, sliders, radio buttons and many others. As an example of a graphical interface, let's look at figure 2.</p>
<p dir="auto"><img src="https://pp.userapi.com/c824500/v824500053/18d255/VBy9HPtT_9g.jpg" alt="" class=" img-fluid img-markdown" /></p>
<p dir="auto">Figure 2. User interface element</p>
<blockquote>
<p dir="auto">In order to set the focus to the next element (the select element) use alternate pressing the Fn and TAB</p>
</blockquote>
<p dir="auto"><strong>Inputbox</strong> represents the input area of the text information on the screen with a fixed height of 50 px. The width can be set by the user, but cannot be less than 32 px. At the top is the inscription (for example: Enter user name), note that at the end will automatically be added the symbol '<strong>:</strong>'. At the bottom is a rectangular area in which the user can enter data from the keyboard. When you focus on this element-the bottom of the backlight. To change the value, use the letters and numbers keys on the keyboard.</p>
<p dir="auto"><strong>Textbox</strong> is an area where text information is displayed on the screen. Dimensions can be user-defined, but cannot be smaller than the size of a single character. This element consists of one part. The text fits over the entire area and does not go beyond. There is no focus on this element.</p>
<p dir="auto"><strong>Waitingbar</strong> is an area for displaying graphical information on a screen with a fixed height of 50 px. The width can be set by the user, but cannot be less than 12 px. At the top is the inscription (for example: Connection to Wi-Fi), note that at the end will automatically be added the symbol '<strong>:</strong>'. At the bottom is a rectangular area, which is painted periodically orange and black squares. There is no focus on this element.</p>
<p dir="auto"><strong>Progressbar</strong> is an area for displaying graphical information on a screen with a fixed height of 50 px. The width can be set by the user, but cannot be less than 12 px. At the top is the inscription (for example: Times of the check), note that at the end will automatically be added the symbol '<strong>:</strong>'. In the lower part is a rectangular area that is colored according to the value specified (10% red, 30% orange, 80% green and 100% blue color). There is no focus on this element.</p>
<p dir="auto"><strong>Selectbox</strong> represents the text information selection area on the screen with a fixed height of 50 px. The width can be set by the user, but cannot be less than 44 px. At the top is the inscription (for example: Mode), note that at the end will automatically be added the symbol '<strong>:</strong>'. At the bottom is a rectangular selection area where the user can select data from the keyboard. To change the value, press the <strong>Fn</strong> key, then <strong>K / M</strong> or similar <strong>up / down</strong> arrows.</p>
<p dir="auto"><strong>Checkbox</strong> represents the input area of a single value (true/false) on a screen with a fixed height of 32 px. The width can be set by the user, but cannot be less than 44 px. On the left side there is a flag (if it is colored, true, if not - false). On the right side is the inscription (for example: Remember password). To remove or set the flag, press the <strong>SPACE</strong> key.</p>
<p dir="auto"><strong>Button</strong> represents the call area of any user-defined function (with a void signature (String*)) with a fixed height of 32 px. The width can be set by the user, but cannot be less than 22 px. In the center is the inscription (for example: Launch). A distinctive feature of this element is the support of icons from the standard set (Fig. 3). To press the button, press the <strong>SPACE</strong> key.</p>
<p dir="auto"><img src="https://pp.userapi.com/c824500/v824500053/18d2c3/3E8ARj5qlsw.jpg" alt="" class=" img-fluid img-markdown" /></p>
<p dir="auto">Figure 3. Standard icon codes 24 x 24 px</p>
<p dir="auto">If the icon is connected, the minimum width will be 51 px.</p>
<p dir="auto"><strong>Rangebox</strong> represents the selection of an integer value from a given range with a fixed height of 50 px. The width can be set by the user, but cannot be less than 32 px. At the top is the inscription (for example: Speed), note that at the end will automatically be added the symbol '<strong>:</strong>'. At the bottom is the area containing the strip and the adjacent slider. To change the value, press the <strong>Fn</strong> key, then <strong>N / $</strong> or similar <strong>left / right</strong> arrows.</p>
<p dir="auto"><strong>List of components for the lesson:</strong></p>
<ul>
<li>PC/MAC;</li>
<li>M5STACK;</li>
<li>FACES;</li>
<li>FACES Keyboard;<br />
-USB-C cable from standard set;</li>
<li>colored wires from the standard set (type socket-plug);</li>
<li>prototype Board for soldering 5 x 7 cm;</li>
<li>soldering iron 40 or 60 W;</li>
<li>rosin soldering;</li>
<li>tin soldering;</li>
<li>scissors;</li>
<li>resistor 36 ohms (1 PC.);</li>
<li>160K resistor (1 PC .);</li>
<li>chip 74HC595N (1 PC .);</li>
<li>resistor 220 Ohm (1 PC.);</li>
<li>LEDs: orange, green, yellow, red (4 PCs.);</li>
<li>powerful transistor BC337 (1 PC.);</li>
<li>resistor 100 kOhm (1 PC.);</li>
<li>DC motor (1 PC.).</li>
</ul>
<h2>Let's start!</h2>
<h3>Step 1. Install the M5 UI library</h3>
<p dir="auto">Follow the link M5 UI for Arduino IDE in the section <strong>Downloads</strong>(at the bottom of this page) and download the archive with the library from GitHub (Fig. 3.1).</p>
<p dir="auto"><img src="https://pp.userapi.com/c845019/v845019100/bac3a/RgQ5whKjRic.jpg" alt="" class=" img-fluid img-markdown" /></p>
<p dir="auto">Figure 3.1. Click the Clone or download button, Then download ZIP</p>
<p dir="auto">Run the Arduino IDE and add the downloaded archive (Fig. 3.2).</p>
<p dir="auto"><img src="https://pp.userapi.com/c830309/v830309356/15f0d4/jFHCVhL_NtQ.jpg" alt="" class=" img-fluid img-markdown" /></p>
<p dir="auto">Figure 3.2. Click Sketch, Include Library, Add .ZIP Library...</p>
<p dir="auto">After that, the library will be successfully added. That's all.</p>
<h3>Step 2. Installation and tools of M5 UI Designer</h3>
<p dir="auto">Similarly, click the M5 UI Designer for Arduino IDE link in the <strong>Downloads</strong> section (at the bottom of this page) and download the library archive from GitHub to your desktop, then extract the content and open the index document.html using a browser (beta-version works only under browsers on Chrome engine) (Fig. 3.4)</p>
<p dir="auto"><img src="https://pp.userapi.com/c849428/v849428356/424d2/0Cwopsj1gbo.jpg" alt="" class=" img-fluid img-markdown" /></p>
<p dir="auto">Figure 3.4</p>
<p dir="auto">This completes the installation of the tool (Fig. 3.5).</p>
<p dir="auto"><img src="https://pp.userapi.com/c849428/v849428356/424f5/ziGE6-kobP8.jpg" alt="" class=" img-fluid img-markdown" /></p>
<p dir="auto">Figure 3.5. M5 UI Designer</p>
<h3>Step 3. Enter key-special (⊙_⊙)</h3>
<p dir="auto">Imagine this situation-the user has entered the necessary information in the same Inputbox and he needs to process it, for example: send somewhere. How do I tell M5 that the user has completed input? That's right-press Enter (as one of the options).<br />
Anywhere in the code, you can always bind a user-defined function to the Enter key, as long as the signature of the user - defined function is as follows void (String*).</p>
<pre><code>void userFunction1(String* rootVar) {
	// reaction after pressing the Enter key
}

...
UIEnter = userFunction1;
</code></pre>
<h3>Step 4. Morse code, Inputbox and Textbox (^_^♪)</h3>
<p dir="auto">Let's add our first element-Inputbox. In it we will enter the text and after pressing the Enter key will hear from the speaker Morse code (Fig. 4).</p>
<p dir="auto"><img src="https://pp.userapi.com/c824500/v824500227/18b695/743qKW2DLmA.jpg" alt="" class=" img-fluid img-markdown" /></p>
<p dir="auto">Figure 4. Morse code</p>
<p dir="auto">Open M5 UI Designer, drag and drop Inputbox and Textbox, set width and headers. In Tools &gt; User Functions, click the yellow lightning icon and enter the name of the new Morse user function. Then, in the Properties &gt; Enter key section, select Morse (Fig. 4.1).</p>
<p dir="auto"><img src="https://pp.userapi.com/c824500/v824500100/185fdc/m0Ya6SK0XpM.jpg" alt="" class=" img-fluid img-markdown" /></p>
<p dir="auto">Figure 4.1.</p>
<p dir="auto">Select all the text from the Source section and copy it to the Arduino IDE.</p>
<pre><code>/* User functions: */
void Morse(String* rootVar) {
 int MorseCodes[] =
 {
  0,1,-1,-1, // A
  1,0,0,0, // B
  1,0,1,0, // C
  1,0,0,-1, // D
  0,-1,-1,-1, // E
  0,0,1,0,  //F
  1,1,0,-1, // G
  0,0,0,0,  // H
  0,0,-1,-1,  // I
  0,1,1,1, // J
  1,0,1,-1, // K
  0,1,0,0, // L
  1,1,-1,-1, // M
  1,0,-1,-1,  // N
  1,1,1,-1, // O
  0,1,1,0,  // P
  1,1,0,1,  // Q
  0,1,0,-1, // R
  0,0,0,-1, // S
  1,-1,-1,-1, // T
  0,0,1,-1, // U
  0,0,0,1,  // V
  0,1,1,-1, // W
  1,0,0,1,  // X
  1,0,1,1, // Y
  1,1,0,0 // Z
 };
 for (int i = 0; i &lt; UIInputbox_v05700a.length(); i++) {
  char chr = UIInputbox_v05700a[i];
  if (chr == ' ')
  {
    M5.Speaker.mute();
    delay(350);
  }
  else
  {
    int chrNum = (chr - 'a') * 4;
    for (int j = chrNum; j &lt; (chrNum + 4); j++)
    {
      M5.Speaker.tone(440);
      if (MorseCodes[j] == 0)
        delay(50);
      else if (MorseCodes[j] == 1)
        delay(200);
      M5.Speaker.mute();
      delay(150);
    }
  }
 }
}
</code></pre>
<p dir="auto">As you can see - the entire code framework generated by M5 UI Designer remained absolutely unchanged in the standard form. The only thing we have changed is the custom Morse function. It's very simple :) (Fig. 4.2).</p>
<p dir="auto"><img src="https://pp.userapi.com/c847019/v847019704/b6da9/4WsWaJpl6b4.jpg" alt="" class=" img-fluid img-markdown" /></p>
<p dir="auto">Figure 4.2</p>
<h3>Step 5. Bruteforce and Waitingbar ≧ ( ◕ ‿ ‿ ◕ ) ≦</h3>
<p dir="auto">Similarly, we add Waitingbar. We will generate an 8-bit random code and then select it. The progress bar will just Waitingbar. Once the code is matched Waitingbar will be hidden. The process will start after pressing the Enter key (Fig. 5).</p>
<p dir="auto"><img src="https://pp.userapi.com/c847018/v847018247/b3d77/tyYQRL08b9Q.jpg" alt="" class=" img-fluid img-markdown" /></p>
<p dir="auto">Figure 5.</p>
<p dir="auto">In this example, we modify the default layer function by adding void UIDiable(bool, String*) after enumerating the elements. This is to ensure that the Waitingbar is hidden for the duration of the inactivity.</p>
<pre><code>/* Function for layer default: */
void LayerFunction_default(String* rootVar) {
 /* UI Elements */
 ...
 UIDisable(true, &amp;UIWaitingbar_yksk2w8);
}
</code></pre>
<blockquote>
<p dir="auto"><strong>void UIDisable(bool, String*)</strong> or <strong>void UISet (String*, int)</strong> used to hide an element. Where <strong>bool</strong> - can be set to <strong>true</strong>/<strong>false</strong> i.e. <strong>hide</strong>/<strong>show</strong> element; <strong>String*</strong> - pointer to rootVar (root variable) element.</p>
</blockquote>
<p dir="auto">Now add the contents of the void Brutforce(String) function*):</p>
<pre><code>/* User functions: */
void Brutforce(String* rootVar) {
  /* make random original key */
  uint8_t okey = random(0, 256); 
  String okeyString = "";
  for (int i = 0; i &lt; 8; i++) {
    okeyString += String((okey &gt;&gt; i) &amp; 1);
  }
  UISet(&amp;UITextbox_sxjzx0g, okeyString); // set value for Textbox
  
  UIDisable(false, &amp;UIWaitingbar_yksk2w8); // show the Waitingbar

  uint8_t key;
  
  while (true) {
    key++;
    String keyString = String();
    for (int i = 0; i &lt; 8; i++) {
      keyString += String((key &gt;&gt; i) &amp; 1);
    }
    UISet(&amp;UITextbox_eyar2x, keyString);
    Serial.print(key);
    Serial.print(" ");
    Serial.println(okey);
    if (key == okey) break;
    M5.Speaker.tone(800);
    delay(40);
    M5.Speaker.mute();
  }
  UIDisable(true, &amp;UIWaitingbar_yksk2w8);
  M5.Speaker.tone(600);
  delay(75);
  M5.Speaker.mute();
  M5.Speaker.tone(800);
  delay(75);
  M5.Speaker.mute();
  M5.Speaker.tone(500);
  delay(75);
  M5.Speaker.mute();
}
</code></pre>
<blockquote>
<p dir="auto">To set the value for an element, use the <strong>void UISet(String*, String)</strong> or <strong>void UISet(String*, int)</strong> function. Where <strong>String*</strong> is a pointer to the rootVar (root variable) of the element;<strong>String</strong> or <strong>int</strong> is the new value.</p>
</blockquote>
<p dir="auto">Now run and see what happened (Fig. 5.1).</p>
<p dir="auto"><img src="https://pp.userapi.com/c847019/v847019704/b6dbd/-KlB50JW9Is.jpg" alt="" class=" img-fluid img-markdown" /></p>
<p dir="auto">Figure 5.1</p>
<h3>Step 6. BatteryCheck and Progressbar Σ(O_O)</h3>
<p dir="auto">Let's make a tester charge conventional finger batteries type A, AA, AAA. Indication will be carried out using the Progressbar in percentage terms, and in addition at the bottom using Textbox will display the voltage in mV (Fig. 6).</p>
<p dir="auto"><img src="https://pp.userapi.com/c824409/v824409536/19e856/9WKqnmbwcLU.jpg" alt="" class=" img-fluid img-markdown" /></p>
<p dir="auto">Figure 6.</p>
<p dir="auto">Here we modify the layer function</p>
<pre><code>/* Function for layer default: */
void LayerFunction_default(String* rootVar) {
 /* To open this layer use: */
 ...
 // BattaryCheck
 while (true) {
  int voltage = analogRead(35) * 3400 / 4096;
  int percentage = voltage * 100 / 1600;
  UISet(&amp;UIProgressbar_1mlmhcu, percentage);
  UISet(&amp;UITextbox_gtaetjh, voltage);
  delay(500);
 }
}
</code></pre>
<p dir="auto">Constantly, every 500 MS, in the cycle we will take readings from the ADC port 0 (pin 35).<br />
Then we will calculate the voltage: 3400 mV is the reference voltage, 4096 is the resolution of the ADC. The switching circuit is shown in figure 6.1.</p>
<blockquote>
<p dir="auto">Note-M5 Bottom is used instead of FACES</p>
</blockquote>
<p dir="auto"><img src="https://pp.userapi.com/c845120/v845120386/afaaf/UEASqM1ywEc.jpg" alt="" class=" img-fluid img-markdown" /></p>
<p dir="auto">Figure 6.1. Visual scheme of switching on the built-in ADC to the finger battery</p>
<p dir="auto">The device works great! Now you have a great tool to check the batteries (Fig. 6.2).</p>
<p dir="auto"><img src="https://pp.userapi.com/c847019/v847019704/b6dd7/50Vh6ZzuvHI.jpg" alt="" class=" img-fluid img-markdown" /></p>
<p dir="auto">Figure 6.2</p>
<h3>Step 7. LEDshift and Selectbox ( ◡ ‿ ◡  *)</h3>
<p dir="auto">Take four LEDs (orange, green, red and yellow), connect them through the shift register 74HC595N to M5 according to the scheme in figure 7.</p>
<p dir="auto"><img src="https://pp.userapi.com/c830608/v830608437/169343/OCbiMso8YQY.jpg" alt="" class=" img-fluid img-markdown" /></p>
<p dir="auto">Figure 7. Wiring the LEDs to the M5 via the shift register</p>
<p dir="auto">Create a graphical interface using M5 UI Designer, as in the previous examples, and copy the code (Fig. 7.1).</p>
<p dir="auto"><img src="https://pp.userapi.com/c845120/v845120757/b5d7c/7Oj2TrIgYJ8.jpg" alt="" class=" img-fluid img-markdown" /></p>
<p dir="auto">Figure 7.1.</p>
<p dir="auto">Now let's modify the code.</p>
<p dir="auto">Add the pin numbers on the M5 for connecting the shift register 74HC595N after RootVar's:</p>
<pre><code>/* RootVar's for UI elements (note: not edit manually) */
...
// Shift register pinout
int SH_CP = 17;
int ST_CP = 2;
int DS = 5;
</code></pre>
<p dir="auto">Next, we add the contents of the void SelectColor(String) function*):</p>
<pre><code>/* User functions: */
void SelectColor(String* rootVar) {
  int led = UIOptionValue(&amp;UISelectbox_6foo6h).toInt();
  digitalWrite(ST_CP, LOW);
  shiftOut(DS, SH_CP, MSBFIRST, led);
  digitalWrite(ST_CP, HIGH);
  delay(100);
}
</code></pre>
<blockquote>
<p dir="auto">In order to get selected option from Selectbox using function <strong>String UIOptionValue(String*)</strong>.</p>
</blockquote>
<p dir="auto">Now you need to fill the Selectbox with options. to do this, we add 5 lines of code to the very beginning of the layer function:</p>
<pre><code>/* Function for layer default: */
void LayerFunction_default(String* rootVar) {
 // add options to Selectbox
 UIOption("OFF", "0", &amp;UISelectbox_6foo6h);
 UIOption("RED", "17", &amp;UISelectbox_6foo6h);
 UIOption("YELLOW", "3", &amp;UISelectbox_6foo6h);
 UIOption("GREEN", "5", &amp;UISelectbox_6foo6h);
 UIOption("ORANGE", "9", &amp;UISelectbox_6foo6h);
 ...
}
</code></pre>
<blockquote>
<p dir="auto">To add an option to the Selectbox, use the <strong>void UIOption(String, String, String*)</strong> function. Where the first <strong>String</strong> is the signature of the option that the user sees; the second <strong>String</strong> is the value of the option that is hidden from the user; <strong>String*</strong> is a pointer to the rootVar (root variable) of the element</p>
</blockquote>
<p dir="auto">At the end, add three lines after the comment below. Thus, we will set up the M5 contacts to output:</p>
<pre><code>void setup() {
 ...
 /* Prepare user's I/O. For example pinMode(5, OUTPUT); */
 pinMode(SH_CP, OUTPUT);
 pinMode(ST_CP, OUTPUT);
 pinMode(DS, OUTPUT);
 ...
}
</code></pre>
<p dir="auto">That's it! :) (fig. 7.2).</p>
<p dir="auto"><img src="https://pp.userapi.com/c847019/v847019704/b6dea/vKWe_4Vp-Fo.jpg" alt="" class=" img-fluid img-markdown" /></p>
<p dir="auto">Figure 7.2</p>
<h3>Step 8. SmartDrill and team from Rangebox, Checkbox, Button (｡• ᵕ •｡`)</h3>
<p dir="auto">What can combine Rangebox, Checkbox and Button? Correct! - drilling machine. Take a DC motor (for example, from the cassette player), transistor (to the power came), resistor to block the current base, a few wires, breadboard and collect! Sometimes it is necessary to make several holes one by one, and sometimes it is necessary to make only one, so there is an idea to allocate some time to the drill, and then turn it off automatically: here we come to the aid of the Checkbox.</p>
<p dir="auto"><img src="https://pp.userapi.com/c849536/v849536704/3fbab/8DCb9Agoec0.jpg" alt="" class=" img-fluid img-markdown" /></p>
<p dir="auto">Figure 8</p>
<p dir="auto">With Rangebox we will adjust the supply voltage on the motor. The button will start and stop the process (Fig. 8). Please note-the button with the icon ;)</p>
<p dir="auto">The Enter button here is not useful to us, so Enter key for all elements will be empty (zero).<br />
Instead, we will call the custom Drill function using The callback property for the button.</p>
<p dir="auto">What's code? After Rootvar's add bool startStatus, which will allow the program to understand whether the engine is running or not.</p>
<pre><code>/* RootVar's for UI elements (note: not edit manually) */
...
// User's variables
bool startStatus = false;
</code></pre>
<p dir="auto">Fill the user-defined function void Drill(String*):</p>
<pre><code>void Drill(String* rootVar) {
  startStatus = (startStatus) ? false : true;
  if (startStatus)
  {
    int power = UIRangebox_ztj619h.toInt() * 255 / 100;
    dac_out_voltage(DAC_CHANNEL_1, power);
    if (UICheckbox_1n9gs0b == "true")
    {
      UICaption("WAIT", &amp;UIButton_enhu9fc);
      delay(25000);
      Drill(0);
      return;  
    }
    UICaption("STOP", &amp;UIButton_enhu9fc);
  }
  else
  {
    dac_out_voltage(DAC_CHANNEL_1, 0);
    UICaption("START", &amp;UIButton_enhu9fc);
  }
}
</code></pre>
<blockquote>
<p dir="auto">To set the value on the analog port, use the function <strong>dac_out_voltage (DAC_CHANNEL_1, int)</strong>. Where <strong>DAC_CHANNEL_1</strong> - channel number (pin 25), <strong>int</strong> - value.</p>
</blockquote>
<p dir="auto">;</p>
<blockquote>
<p dir="auto">In order to change the title of any of the UI elements use the function <em><em>UICaption(String, String</em>)</em>*. Where <strong>String</strong> - new header; <strong>String*</strong> - pointer to rootVar (root variable) of the element</p>
</blockquote>
<p dir="auto">Hurray! Now you can try drilling (Fig. 8.1).</p>
<p dir="auto"><img src="https://pp.userapi.com/c849536/v849536704/3fc0c/QRiUEkOQ0ZE.jpg" alt="" class=" img-fluid img-markdown" /></p>
<p dir="auto">Figure 8.1</p>
<h3>Step 9. Launch!</h3>
<p dir="auto">In the section <strong>"Downloads"</strong> attached video demonstration. This completes the lesson.</p>
<h2>Downloads</h2>
<ul>
<li>M5 UI for Arduino IDE (GitHub): <a href="https://github.com/dsiberia9s/M5_UI" title="https://github.com/dsiberia9s/M5_UI" target="_blank" rel="noopener noreferrer nofollow ugc">https://github.com/dsiberia9s/M5_UI</a></li>
<li>M5 UI Designer for Arduino IDE (GitHub): <a href="https://github.com/dsiberia9s/M5_UI_Designer_for_Arduino_IDE" title="https://github.com/dsiberia9s/M5_UI_Designer_for_Arduino_IDE" target="_blank" rel="noopener noreferrer nofollow ugc">https://github.com/dsiberia9s/M5_UI_Designer_for_Arduino_IDE</a></li>
<li>Demonstration video "Morse" (YouTube): <a href="https://youtu.be/ZYIfTDb_r80" title="https://youtu.be/ZYIfTDb_r80" target="_blank" rel="noopener noreferrer nofollow ugc">https://youtu.be/ZYIfTDb_r80</a></li>
<li>Demonstration video "Bruteforce" (YouTube): <a href="https://youtu.be/IfZaFtWYyFA" title="https://youtu.be/IfZaFtWYyFA" target="_blank" rel="noopener noreferrer nofollow ugc">https://youtu.be/IfZaFtWYyFA</a></li>
<li>Demonstration video "BatteryCheck"(YouTube): <a href="https://youtu.be/TgceYjgONd8" title="https://youtu.be/TgceYjgONd8" target="_blank" rel="noopener noreferrer nofollow ugc">https://youtu.be/TgceYjgONd8</a></li>
<li>Video demonstration "LEDshift"(YouTube): <a href="https://youtu.be/vDMsIPcURgc" title="https://youtu.be/vDMsIPcURgc" target="_blank" rel="noopener noreferrer nofollow ugc">https://youtu.be/vDMsIPcURgc</a></li>
<li>Video demonstration "SmartDrill"(YouTube): <a href="https://youtu.be/uDhNmWwTD4Q" title="https://youtu.be/uDhNmWwTD4Q" target="_blank" rel="noopener noreferrer nofollow ugc">https://youtu.be/uDhNmWwTD4Q</a></li>
</ul>
]]></description><link>https://community.m5stack.com/topic/289/lesson-13-1-ui-full-manual</link><generator>RSS for Node</generator><lastBuildDate>Mon, 20 Apr 2026 19:42:51 GMT</lastBuildDate><atom:link href="https://community.m5stack.com/topic/289.rss" rel="self" type="application/rss+xml"/><pubDate>Tue, 07 Aug 2018 12:43:19 GMT</pubDate><ttl>60</ttl></channel></rss>