Your First IoT Project

In this tutorial, we'll explore a unique aspect of the Barracuda App Server. While it supports standard protocols like HTTPS client, WebSockets, MQTT, and more, our focus will differ. We'll guide you through setting up your own managed IoT server on-premises or online, all based on code powered by the Barracuda App Server, including the cloud server.

This approach, successfully applied in several IoT projects at Real Time Logic, offers a practical way to establish a personalized IoT environment. By the end of this tutorial, you will clearly understand how to customize and manage your IoT server using the Barracuda App Server's capabilities.

This tutorial provides a hands-on experience with Lua code examples that are ready to run on an ESP32 powered by Xedge32.

This tutorial builds upon the LED blink example in the tutorial Your First Xedge32 Project and shows how to turn an LED's on/off state through an online IoT cloud server. But before we jump into IoT, we'll enhance our hardware setup by adding a button.

Controlling an LED Using a Button

Unlike traditional methods that require constant polling for GPIO changes, Xedge32 allows for a more efficient approach. We'll use an interrupt-driven mechanism, where a button press instantly triggers a Lua callback function.

Advantages of Xedge32's GPIO Approach:

  • Efficiency: Eliminates the need for continuous polling using timers.
  • Responsiveness: Immediate response to hardware inputs like button presses.

Implementing the Button Functionality

The cfgButton Function:

We'll encapsulate the button-related functionality in a reusable function called cfgButton, which simplifies setting up a GPIO pin as a button input and is easily reusable for future projects.

Parameters of cfgButton:

  1. pin: Specifies the GPIO pin connected to the button.
  2. cb: Defines the callback function to execute upon a button press.
local function cfgButton(pin,cb)
   local cfg={
      pulldown=true,
      type="POSEDGE",
      callback=cb
   }
   return esp32.gpio(pin,"IN", cfg)
end

button=cfgButton(1, function() trace"Button clicked" end)

Example 1: Button click test code

  • Configuration Table (cfg):
    • pulldown: Enables the internal pulldown resistor, which makes the GPIO state low by default.
    • type: Set to "POSEDGE", indicating that the callback triggers on the positive edge (i.e., when the button is pressed).
    • callback: Assigns the user-defined callback function (cb) to be executed on button press.
  • GPIO Configuration:
  • Button Test Code:
    • button = cfgButton(1, function() trace"Button clicked" end): Configures GPIO pin 1 for the button. When the button is pressed, it prints "Button clicked" in the trace log.

We use GPIO one for the button, but you can use any GPIO pin. Just make sure to adjust the examples accordingly. The following figure shows our test bench:

Figure 1: ESP32's 3.3V wired to button pin 1 and GPIO 1 wired to button pin 2.

To add the button functionality to your Xedge32 project:

  1. Copy the code from Example 1.
  2. Open the Xedge32 Integrated Development Environment (IDE) and create a new Lua file in the same application as your running LED blink script. See the tutorial Your First Xedge32 Project if you do not have this script running.
  3. Paste the copied code into this file.

The Xedge32 IDE allows for seamless development of new features, even while other files run; thus, your LED blink script should continue to operate while testing the button code.

The screenshot below shows the original blinkled.xlua file from the tutorial "Your First Xedge32 Project" and the new button.xlua script.

Figure 2: The LED and button scripts work independently.

In the above setup, clicking the button triggers the "Button clicked" message in the console. This output indicates that the button's callback function is functioning as expected, providing a simple way to verify the button's responsiveness.

The key aspect to note here is Xedge32's ability to handle concurrent execution of scripts. The button.xlua script runs in parallel with the blinkled.xlua script without any interference, showing Xedge32's ability to run scripts while developing a new script.

Designing the IoT Bridge

In the following example, we merge the button code from Example 1 with the LED configuration from the timer blink example. To achieve this, we introduce two new functions: manageLed and cfgLed:

  1. Function manageLed: This function handles the button's state management. It ensures that the button's interactions are effectively translated into actions for the LED.
  2. Function cfgLed: This function sets up the GPIO settings for the LED. It encapsulates the hardware configuration for the LED.

At the beginning of the example, you'll find a table containing LED state information. This table acts as an array of LED state objects. In the final example, we'll expand on the LED state object to include additional LED state information.

Towards the end of the example, there's another table named hwContainer. Similar to the first table, it's a list of objects. Each object in this table maintains a relationship between an LED and a button. This structure makes it easy to scale the system by adding more LEDs and buttons - simply extend these tables to include additional HW components.

local leds={
   {
      on=false
   }
}

local hwContainer -- forward decl.

local function manageLed(index)
   local led=leds[index]
   local state = not led.on -- toggle
   led.on = state -- update
   hwContainer[index].led:value(not state) -- set LED: low=on
   trace("Clicked:",index,state)
end

local function cfgButton(pin,cb)
   local cfg={
      pulldown=true,
      type="POSEDGE",
      callback=cb
   }
   return esp32.gpio(pin,"IN", cfg)
end

local function cfgLed(pin)
   local led=esp32.gpio(pin,"OUT")
   led:value(true) -- Set high: led off
   return led
end

hwContainer={
   {
      button=cfgButton(1, function() manageLed(1) end),
      led=cfgLed(9)
   }
}


function onunload()
   trace"Closing app"
   -- Release HW
   for _,obj in ipairs(hwContainer) do
      obj.button:close()
      obj.led:close()
   end
end

Example 2: Combined Button and LED Test Code

Begin the development of your final IoT application by creating a new app using Xedge32. First, ensure you stop the current application. This step is required because only one program can access a specific hardware object at any time. You will get error messages such as "gpio in use" if you do not stop the application.

Please follow the steps below to run Example 2:

  1. Stop the currently running application.
  2. Create a new application and give it the name "IoT".
  3. create a file named "SMQ-LED.xlua" in this new application.
  4. Copy Example 2 above and paste into the "SMQ-LED.xlua" file; save it to start the program.
  5. You should now be able to toggle the LED's on/off state by clicking the button.

The Final IoT Example

Building on Example 2, Example 3 introduces SMQ integration. SMQ, a unique publish/subscribe protocol included in the Barracuda App Server, allows our application to function as an SMQ client. This client connects to an SMQ broker, which can be found at https://simplemq.com/.

Before Diving into the Final Example:

If you're new to SMQ, check out the following resources to familiarize yourself with the pub/sub protocol:

local smq,hwContainer,ipaddr -- forward decl.

local leds={
   {  -- Information required by the browser UI
      id=1, -- LED id is index into hwContainer[] and leds[]
      name="LED 1",
      color="yellow",
      on=false
   }
}

local function manageLed(index, state)
   local led=leds[index]
   if nil == state then -- if local button clicked
      state = not led.on -- toggle
      trace("Button -> index:",index,"state:",state)
   else
      trace("Browser -> index:",index,"state:",state)
   end
   led.on = state -- update
   hwContainer[index].led:value(not state) -- set LED: low=on
   -- Create a two byte binary message with index and LED state
   local msg=ba.bytearray.create(2)
   msg[1],msg[2]=index,state and 1 or 0
   smq:publish(msg, "/m2m/led/device", "led")
end

local function cfgButton(pin,cb)
   local cfg={
      pulldown=true,
      type="POSEDGE",
      callback=cb
   }
   return esp32.gpio(pin,"IN", cfg)
end

local function cfgLed(pin)
   local led=esp32.gpio(pin,"OUT")
   led:value(true) -- Set high: led off
   return led
end

hwContainer={
   {
      button=cfgButton(1, function() manageLed(1) end),
      led=cfgLed(9)
   }
}

-- Function sends a JSON message when one or all browsers need our LED state info
local function pubDeviceInfo(tid)
   -- We use ipaddr for the text shown in the left pane tab in the
   -- browser's user interface
   local payload={
      ipaddr=ipaddr,
      devname="Example code for the tutorial: Your First IoT Project",
      leds=leds
   }

   -- Send to browser with topic ID (tid) if set or publish to all
   -- browsers if 'tid' not set.
   smq:publish(payload, tid or "/m2m/led/device", "devinfo")
end

-- Create SMQ instance and connect to https://simplemq.com/smq.lsp
-- See https://simplemq.com/m2m-led/
-- Documentation: realtimelogic.com/ba/doc/?url=SMQC.html
smq=require"smq.client".create("https://simplemq.com/smq.lsp",{uid=esp32.mac()})

-- Called when SMQ connects
function smq.onconnect(tid, rnd, ip)
   ipaddr=ip
   -- "self" is for subscribing to messages sent directly to this client
   -- See: realtimelogic.com/ba/doc/?url=SMQ.html#PublishersAddress
   smq:subscribe("self",{
                    onmsg=function(payload)
                       -- Browser sends a two byte array (index, state)
                       local msg=ba.bytearray.create(payload)
                       local index,state=msg[1],msg[2]==1
                       manageLed(index, state)
                    end
                 })
   -- Subscribe to messages sent by new browsers 
   smq:subscribe("/m2m/led/display",{
                    onmsg=function(payload,ptid)
                       -- Update new browser with our LED state info
                       pubDeviceInfo(ptid) -- one-to-one msg
                    end
                 })
   -- Inform all connected browser when device connects
   pubDeviceInfo() -- one-to-many msg
   trace("SMQ connected, our public IP:",ip)
end

function smq.onclose(message,canreconnect)
   trace"SMQ disconnected"
   return canreconnect
end

function onunload()
   trace"Closing app"
   smq:close()
   -- Release HW
   for _,obj in ipairs(hwContainer) do
      obj.button:close()
      obj.led:close()
   end
end

Example 3: The Final IoT Button and LED Example Program

Running Example 3:

If you've successfully tested Example 2, transitioning to Example 3 should be straightforward. Example 3 is designed to connect with the SMQ broker, and the one LED in the example will appear in the SMQ-LED Web User Interface.

  1. Copy the Source Code for Example 3.
  2. Update the SMQ-LED.xlua File:
    • Use the Xedge32 Integrated Development Environment (IDE) and paste the Example 3 source code into the SMQ-LED.xlua file.
    • This action replaces the code from Example 2 with that of Example 3.
  1. Save the File in Xedge32: Saving SMQ-LED.xlua will automatically stop Example 2 and start Example 3.
  2. Interact with the SMQ-LED Web User Interface:
    • Open multiple views of the SMQ-LED Web User Interface.
    • Use the button on the web interface and the physical button to toggle the LED state.

Understanding How Example 3 Functions

Example 3, written in Lua, forms part of a comprehensive tutorial series spanning multiple programming languages, offering a foundational insight into SMQ. The tutorial titled Controlling Devices Over the Internet of Things explains the publish/subscribe messaging paradigm employed in Example 3. It also shows how you can run the C-language variant of Example 3.

The online SMQ broker, hosted on simplemq.com, operates within a clustered setup. If your ESP32 device is connected to simplemq.com, make sure to check out the High-Availability IoT Cluster Example. You should see your own ESP32 connected to this cluster.

Exercise 1: Expanding Your ESP32 Setup

In this exercise, you'll take your ESP32 project to the next level by adding more interactive elements. Follow these steps to enrich your setup:

  1. Hardware Assembly: Start by wiring your ESP32 with additional LEDs and buttons. Refer to Figure 3 below for guidance on the setup. The goal is to expand your current configuration to include four LEDs and buttons.
  2. Code Modification:
    • Update the leds array in your code to incorporate the new LEDs.
    • Similarly, expand the hwContainer array to include the additional buttons.
  1. Integration with SMQ-LED Web User Interface:
    • Once your device connects to the SMQ broker, all four LEDs should be visible and controllable through the SMQ-LED Web User Interface.
ESP32 LED and button test bench

Figure 3: An ESP32 with four LEDs and four buttons.

Exercise 2: On-Premises IoT Solution or Setting Up Your Own Cloud

The SMQ broker hosted on simplemq.com is designed to demonstrate the SMQ IoT protocol. This setup can be effortlessly replicated and executed either on your local computer or on your own online cloud server.

On-Premises IoT Solution

In this exercise, we will modify Example 3, where we connected to the SMQ broker at simplemq.com. Instead, you will learn to establish your own on-premises solution using the Mako Server, Xedge32's big brother, right on your own computer. Begin by downloading the Mako Server and exploring its included tutorials. The tutorials include the same broker example as on simplemq.com. Once you have launched the Mako Server tutorials, turn to Example 3 and navigate to line 68 for a simple modification: replace the URL https://simplemq.com/smq.lsp with http://ip-address/smq.lsp, substituting 'ip-address' with your own computer's actual IP address. Finally, hit the run button in Xedge32. This action will disconnect the ESP32 from simplemq.com and connect the ESP32 to the broker now operating on your computer.

Setting Up Your Own Cloud

Setting up your personal online SMQ broker is straightforward. The tutorial titled How To Set Up an Environmentally Friendly IoT Solution provides a comprehensive guide covering all the necessary steps. Once you have completed this tutorial, update Example 3 by altering the URL at line 68 and redirecting it to your newly established online cloud server.

IoT Foundation

This tutorial is designed to introduce SMQ rather than be a foundation for your SMQ IoT design.

The IoT Foundation Tutorial includes code to be used as a base for a complete IoT solution. It details collecting data from an ESP32, recording it to a database, and displaying it on a web page. The tutorial also demonstrates transitioning the setup from on-premises to an online server. It highlights the use of ChatGPT as a development aid in the early design stages.

What's Next?

This tutorial was just the beginning. To truly master Xedge32, check out our full range of Xedge32 tutorials and take your skills to the next level. You can also find additional Xedge32 examples on GitHub.


Hitting Roadblocks? We're Your Way Forward!

Dive deep into our treasure trove of embedded web server and IoT tutorials designed for enthusiasts like you. Yet, if deadlines loom or challenges arise, remember our experts are on standby. With Real Time Logic, you have the freedom to learn and the assurance of expert support when you need it. Let's bring your project to fruition your way.



OPC-UA

OPC-UA Client & Server

An easy to use OPC UA stack that enables bridging of OPC-UA enabled industrial products with cloud services, IT, and HTML5 user interfaces.

Edge Controller

Edge Controller

Use our user programmable Edge-Controller as a tool to accelerate development of the next generation industrial edge products and to facilitate rapid IoT and IIoT development.

On-Premises IoT

On-Premises IoT Platform

Learn how to use the Barracuda App Server as your On-Premises IoT Foundation.

Embedded Web Server

Barracuda Embedded Web Server

The compact Web Server C library is included in the Barracuda App Server protocol suite but can also be used standalone.

WebSocket Server

Microcontroller Friendly

The tiny Minnow Server enables modern web server user interfaces to be used as the graphical front end for tiny microcontrollers. Make sure to check out the reference design and the Minnow Server design guide.

WebDAV Server

Network File System

Why use FTP when you can use your device as a secure network drive.

HTTP Client

Secure HTTP Client Library

PikeHTTP is a compact and secure HTTP client C library that greatly simplifies the design of HTTP/REST style apps in C or C++.

WebSocket Client

Microcontroller Friendly

The embedded WebSocket C library lets developers design tiny and secure IoT applications based on the WebSocket protocol.

SMTP Client

Secure Embedded SMTP Library

Send alarms and other notifications from any microcontroller powered product.

Crypto Library

RayCrypto C Library

The RayCrypto engine is an extremely small and fast embedded crypto library designed specifically for embedded resource-constrained devices.

Embedded PKI Service

Automatic SSL Certificate Management for Devices

Real Time Logic's SharkTrust™ service is an automatic Public Key Infrastructure (PKI) solution for products containing an Embedded Web Server.

Modbus

Modbus TCP client

The Modbus client enables bridging of Modbus enabled industrial products with modern IoT devices and HTML5 powered HMIs.

Posted in Xedge32