Overview Getting Started Reference Latest News



Here, we will review a basic "Hello World!" example:

You will need an ESP32 device, and PlatformIO.

In this example, we will use a set of interfaces called smart-transducer. So, first of all, you will need to install the client tools on your machine. Add the Pike repository to your sources:

console
$ wget -qO- http://pike.esi.uclm.es/add-pike-repo.sh | sudo sh

And then, install using your favourite package manager, or run the following command:

console
$ sudo apt install smart-transducer

Our goal is to switch on/off the onboard LED, so we will use the ST module, in particular the interface IBool. It has the following signature:

st.ice
module st {
  interface IBool {
    void set(bool v, string sourceAddr);
  };
};

So, open your PlatformIO IDE (I use VS Code), and create a new project. Give it a project name, and choose your board. For this example, I used a DOIT ESP32 DevKit, so my settings are:


Now, edit the platformio.ini file and add a pair of library dependencies: icec and st. Also, I set the serial speed to match the used in the example:

platformio.ini
lib_deps = IceC, st
monitor_speed = 115200

Now, let's delve in the interesting part! Open the src/main.cpp, which is the core of your program. First, include the needed headers: those of IceC, the TCP endpoint and ST:

main.cpp
#include <WiFi.h>

#include <IceC.h>
#include <IceC/platforms/esp8266/TCPEndpoint.h>
#include <IceC/platforms/esp8266/debug.hpp>

#include "st.h"

We also need to declare some basic objects: the Communicator, an Object Adapter and the servant for our LED. Do it in the global scope, to ensure that they are not disposed:

main.cpp
// Some global variables
Ice_Communicator ic;
Ice_ObjectAdapter adapter;
st_IBool servant;

Of course, you need to provide an implementation of every method of your interface. In this case, there is only one method, set(), which will change the LED status:

main.cpp
void st_IBoolI_set(st_IBoolPtr self, Ice_Bool v, Ice_String sourceAddr) {
  digitalWrite(LED_BUILTIN, v ? HIGH : LOW);
}

Now, inside the setup() function, we need to configure the wireless conectivity. For this simple example, we will put the device in AP mode, without credentials:

main.cpp
  String ssid = "hello-node";
  Serial.printf("\n--------\nWiFi: setting up AP as '%s'\n", ssid.c_str());
  WiFi.mode(WIFI_AP);
  WiFi.enableSTA(false);
  WiFi.softAP(ssid.c_str());

And then, initialize the Communicator, and create an Object Adapter (please refer to the ZeroC Ice documentation for more information). For this example, we will listen on port 1234:

main.cpp
  Ice_Communicator_init(&ic);
  TCPEndpoint_init(&ic);

  Ice_Communicator_createObjectAdapterWithEndpoints(
    &ic, "adapter", "tcp -p 1234", &adapter
  );
  Ice_ObjectAdapter_activate(&adapter);

Once the Object Adapter is ready, we can initialize and register the LED object. In this example, I used the identity "led":

main.cpp
  st_IBool_init(&servant);
  Ice_ObjectAdapter_add(&adapter, (Ice_ObjectPtr)&servant, "led");

At last (but not least), you should include on your event loop a call to the middleware engine, just to handle incomming events. So, the loop() function may be:

main.cpp
void loop() {
  Ice_Communicator_loopIteration(&ic);
}

To summarize, your code may be like this:

main.cpp
#include <Arduino.h>
#include <WiFi.h>

#include <IceC.h>
#include <IceC/platforms/esp8266/TCPEndpoint.h>
#include <IceC/platforms/esp8266/debug.hpp>

#include "st.h"

// Some global variables
Ice_Communicator ic;
Ice_ObjectAdapter adapter;
st_IBool servant;

// The servant implementation
void st_IBoolI_set(st_IBoolPtr self, Ice_Bool v, Ice_String sourceAddr) {
  digitalWrite(LED_BUILTIN, v ? HIGH : LOW);
}

void setup() {
  // Common initialization
  Serial.begin(115200);
  pinMode(LED_BUILTIN, OUTPUT);

  String ssid = "hello-node";
  Serial.printf("\n--------\nWiFi: setting up AP as '%s'\n", ssid.c_str());
  WiFi.mode(WIFI_AP);
  WiFi.enableSTA(false);
  WiFi.softAP(ssid.c_str());

  // Initialize the communicator
  Ice_Communicator_init(&ic);
  TCPEndpoint_init(&ic);

  // Create the object adapter
  Ice_Communicator_createObjectAdapterWithEndpoints(
    &ic, "adapter", "tcp -p 1234", &adapter
  );
  Ice_ObjectAdapter_activate(&adapter);

  // Register servant
  st_IBool_init(&servant);
  Ice_ObjectAdapter_add(&adapter, (Ice_ObjectPtr)&servant, "led");

  Serial.println("Ready, waiting events...");
}

void loop() {
  // Wait for events
  Ice_Communicator_loopIteration(&ic);
}

The final step is to compile and upload the binary to your device. Connect it to an USB port, and run the command >platformio: build (or whatever you have in your IDE). Once the process is complete, and your device has restarted, it will create a new WiFi AP, called node-hello. Connect your computer to it (remember, there is no credentials). It will assign you the IP address 192.168.4.2, while the node address will be 192.168.4.1.

Now, if you connected successfully, change the state of your led using the st-client tool:

console
$ st-client -t bool -p "led -o:tcp -h 192.168.4.1 -p 1234" 1
$ st-client -t bool -p "led -o:tcp -h 192.168.4.1 -p 1234" 0

If you see your device LED shining, congratulations!