ESP8266 / ESP32 control IoT with the ESPUI-library Webinterface without HTML-coding

Hi everybody,

some days ago I started learning the ESPUI-library which can be downloaded here

No html-knowledge required.
ESPUI allows to create webinterfaces with a lot of different elements like buttons, switches, sliders etc.
All this is done through pure C++-function calls. You need to no nothing about html

The documentation in the

explains the most important basics.
The examples show different options but are IMHO somehow too much at once
for explaining how it works in detail

Here is a code that combines the preferences-library with ESPUI.
compared to the examples that are comming with the library I changed a lot of variable-names to be more self-explaining.
here is a demo-code that shows how to use tabs
and how to place UI-elements on the tabs.
UI-elements on tabs must be created and accessed different than on non-tabbed wesites

I added my own standard-functions for debugging and connecting to WiFi

This demo-code uses the library MobaTools for controlling a RC-Servo
There are two tabs "Operation" and "Settings"
Tab Operation shows three buttons and a status-text
Tab Settings shows three number-input-fields with Min/Max-values
a button for saving the values into flash and a "set default values" button

I hope this help clarifying some details how to use the ESPUI-library.

If you post your codes just do so

  #define dbg(myFixedText, variableName) \
  Serial.print( F(#myFixedText " "  #variableName"=") ); \
  Serial.println(variableName);

#define dbgi(myFixedText, variableName,timeInterval) \
  do { \
    static unsigned long intervalStartTime; \
    if ( millis() - intervalStartTime >= timeInterval ){ \
      intervalStartTime = millis(); \
      Serial.print( F(#myFixedText " "  #variableName"=") ); \
      Serial.println(variableName); \
    } \
  } while (false);

#include <Preferences.h>     // add sourcecode file
Preferences myPrefInstance;  // create an instance of the object

#include <DNSServer.h>
#include <ESPUI.h>

const byte DNS_PORT = 53;
IPAddress apIP(192, 168, 4, 1);
DNSServer dnsServer;

#if defined(ESP32)
#include <WiFi.h>
#else
#include <ESP8266WiFi.h>
#endif

#include <MobaTools.h>

const byte servoPin = 14; // GPIO 14 is labeled D5
const byte Speed = 230;

MoToServo myServo;
#define ServoMin "700"
#define ServoMax "2300"

unsigned long MyTestTimer = 0;                   // Timer-variables MUST be of type unsigned long
const byte    OnBoard_LED = 2;
unsigned long SwitchStateTimer = 0;


const char *home_ssid     = "FRITZ!Box 7490";
const char *home_password = "";

char ap_ssid[25];
const char* AP_password = "espui";
const char* AP_hostname = "espui";

uint16_t myTab1_ID;
uint16_t myTab2_ID;

uint16_t statusLabel_ID;

uint16_t button1_ID;
uint16_t button2_ID;
uint16_t button3_ID;

uint16_t ServoPos1_ID;
uint16_t ServoPos2_ID;
uint16_t ServoPos3_ID;
uint16_t buttonSave_ID;
uint16_t buttonSetDefault_ID;

#define myNameSpace "ServoPos"
const boolean ReadOnly  = true;
const boolean ReadWrite = !ReadOnly; // not-operator inverts the value

int servoPos1microS;
int servoPos2microS;
int servoPos3microS;


void PrintFileNameDateTime() {
  Serial.println( F("Code running comes from file ") );
  Serial.println( F(__FILE__) );
  Serial.print( F("  compiled ") );
  Serial.print( F(__DATE__) );
  Serial.print( F(" ") );
  Serial.println( F(__TIME__) );
}


// easy to use helper-function for non-blocking timing
boolean TimePeriodIsOver (unsigned long &startOfPeriod, unsigned long TimePeriod) {
  unsigned long currentMillis  = millis();
  if ( currentMillis - startOfPeriod >= TimePeriod ) {
    // more time than TimePeriod has elapsed since last time if-condition was true
    startOfPeriod = currentMillis; // a new period starts right here so set new starttime
    return true;
  }
  else return false;            // actual TimePeriod is NOT yet over
}


void BlinkHeartBeatLED(int IO_Pin, int BlinkPeriod) {
  static unsigned long MyBlinkTimer;
  pinMode(IO_Pin, OUTPUT);

  if ( TimePeriodIsOver(MyBlinkTimer, BlinkPeriod) ) {
    digitalWrite(IO_Pin, !digitalRead(IO_Pin) );
  }
}


void number1Callback(Control* sender, int eventType) {
  Serial.print(" ");
  Serial.print(sender->label);

  Serial.println(sender->value);
  servoPos1microS = atoi(sender->value.c_str());
  dbg("Pos1", servoPos1microS);
}

void number2Callback(Control* sender, int eventType) {
  Serial.print(" ");
  Serial.print(sender->label);

  Serial.println(sender->value);
  servoPos2microS = atoi(sender->value.c_str());
  dbg("Pos2", servoPos2microS);
}


void number3Callback(Control* sender, int eventType) {
  Serial.print(" ");
  Serial.print(sender->label);

  Serial.println(sender->value);
  servoPos3microS = atoi(sender->value.c_str());
  dbg("Pos3", servoPos3microS);
}


void buttonSetDefaultCallback(Control* sender, int eventType) {
  Serial.print("ID: ");
  Serial.print(sender->id);
  Serial.print(" ");
  Serial.println(sender->label);

  if (eventType == B_UP) {
    servoPos1microS = 1100;
    servoPos2microS = 1500;
    servoPos3microS = 1900;
    ESPUI.updateControlValue(ServoPos1_ID, String(servoPos1microS) );
    ESPUI.updateControlValue(ServoPos2_ID, String(servoPos2microS) );
    ESPUI.updateControlValue(ServoPos3_ID, String(servoPos3microS) );

    dbg("Default", servoPos1microS);
    dbg("Default", servoPos2microS);
    dbg("Default", servoPos3microS);
    ESPUI.updateControlValue(statusLabel_ID, "Set positions to default");
  }
}


void  buttonSaveCallback(Control* sender, int eventType) {
  Serial.print("ID: ");
  Serial.print(sender->id);
  Serial.print(" ");
  Serial.println(sender->label);
  if (eventType == B_UP) {
    SafePreferences();
    ESPUI.updateControlValue(statusLabel_ID, "positions saved to flash");
  }
}


void button123Callback(Control* sender, int eventType) {

  uint16_t UI_ID = sender->id;

  switch (eventType) {

    case B_DOWN:
      //Serial.println("Button DOWN");
      break;

    case B_UP:
      Serial.print("Button UP ");
      Serial.print("label ");
      Serial.print(sender->label);
      dbg(" Btn123", UI_ID);

      if (UI_ID == button1_ID) {
        myServo.write(servoPos1microS);
        ESPUI.updateControlValue(statusLabel_ID, "Position 1 clicked");
      }
      
      if (UI_ID == button2_ID) {
        myServo.write(servoPos2microS);
        ESPUI.updateControlValue(statusLabel_ID, "Position 2 clicked");
      }

      if (UI_ID == button3_ID) {
        myServo.write(servoPos3microS);
        ESPUI.updateControlValue(statusLabel_ID, "Position 3 clicked");
      }
      break;
  }
}


void ConnectToWiFi() {
  int myCount = 0;
#if defined(ESP32)
  WiFi.setHostname(AP_hostname); // xxy
#else
  WiFi.hostname(AP_hostname);
#endif

  // try to connect to existing network
  WiFi.begin(home_ssid, home_password);
  Serial.print("\n\nTry to connect to existing network");
  Serial.print(" named #");
  Serial.print(home_ssid);
  Serial.println("#");

  // Wait for connection
  while (WiFi.status() != WL_CONNECTED && myCount < 31) {
    yield(); // very important to execute yield to make it work
    BlinkHeartBeatLED(OnBoard_LED, 50); // blink LED fast during attempt to connect

    if ( TimePeriodIsOver(MyTestTimer, 500) ) { // once every 500 miliseconds
      Serial.print(".");                        // print a dot
      myCount++;

      if (myCount > 30) { // after 30 dots = 15 seconds restart
        Serial.println();
        Serial.print("not connected ");
      }
    }
  }

  if (WiFi.status() == WL_CONNECTED ) {
    Serial.println("");
    Serial.print("Connected to #");
    Serial.print(home_ssid);
    Serial.print("# IP address: ");
    Serial.println(WiFi.localIP());
  }
}

void createOwnAP() {
  // not connected -> create hotspot
  if (WiFi.status() != WL_CONNECTED) {
    Serial.print("\n\n no connection to SSID #");
    Serial.print(home_ssid);
    Serial.println("#\n Creating hotspot");

    WiFi.mode(WIFI_AP);
    delay(100);
    WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));

#if defined(ESP32)
    uint32_t chipid = 0;
    for (int i = 0; i < 17; i = i + 8) {
      chipid |= ((ESP.getEfuseMac() >> (40 - i)) & 0xff) << i;
    }
#else
    uint32_t chipid = ESP.getChipId();
#endif
    snprintf(ap_ssid, 26, "ESPUI-%08X", chipid);
    WiFi.softAP(ap_ssid);
    Serial.print("SSID #");
    Serial.print(ap_ssid);
    Serial.println("#");

    //dnsServer.start(DNS_PORT, "*", apIP);
  }
}

void printWiFiModeAndIP() {
  if (WiFi.getMode() == WIFI_AP) {
    Serial.print("ESP is its OWN accesspoint with SSID ");
    Serial.println(ap_ssid);
    Serial.print("IP address: ");
    Serial.println(WiFi.softAPIP() );
  }
  else {
    Serial.print("ESP connected to existing WLAN named ");
    Serial.println(home_ssid);
    Serial.print("IPAdress: ");
    Serial.println(WiFi.localIP() );
  }
}


void setup() {
  delay(1000);
  Serial.begin(115200);
  delay(1000);
  PrintFileNameDateTime();

#if defined(ESP32)
  WiFi.setHostname(AP_hostname);
#else
  WiFi.hostname(AP_hostname);
#endif

  ConnectToWiFi();
  if (WiFi.status() != WL_CONNECTED) {
    createOwnAP();
  }
  dnsServer.start(DNS_PORT, "*", apIP);
  printWiFiModeAndIP();

  defineUI();
  ESPUI.begin("I am the website created by the ESPUI-Demo");
  LoadPreferences();
  setupServo();
}


void loop() {
  BlinkHeartBeatLED(OnBoard_LED, 500);
  dnsServer.processNextRequest();

  if ( TimePeriodIsOver(MyTestTimer, 1000) ) {
  }

  if ( TimePeriodIsOver(SwitchStateTimer, 5000) ) {
  }
}


void defineUI() {
  // defining the website-tabs
  myTab1_ID = ESPUI.addControl(ControlType::Tab, "Operation", "Operation");
  myTab2_ID = ESPUI.addControl(ControlType::Tab, "Settings",  "Settings");

  // shown above all tabs
  statusLabel_ID = ESPUI.addControl(ControlType::Label, "last action:", "Last Action: none", ControlColor::Turquoise);

  // elements on myTab1_ID
  button1_ID = ESPUI.addControl(ControlType::Button, "Position 1", "Pos 1", ControlColor::Peterriver, myTab1_ID, &button123Callback);
  button2_ID = ESPUI.addControl(ControlType::Button, "Position 2", "Pos 2", ControlColor::Wetasphalt, myTab1_ID, &button123Callback);
  button3_ID = ESPUI.addControl(ControlType::Button, "Position 3", "Pos 3", ControlColor::Wetasphalt, myTab1_ID, &button123Callback);


  // elements on myTab2_ID
  ServoPos1_ID = ESPUI.addControl(ControlType::Number, "Servo position 1 (µseconds):", "1100",  ControlColor::Alizarin, myTab2_ID, &number1Callback);
  ESPUI.addControl(ControlType::Min, "Min-value", ServoMin, ControlColor::None, ServoPos1_ID);
  ESPUI.addControl(ControlType::Max, "Max-value", ServoMax, ControlColor::None, ServoPos1_ID);

  ServoPos2_ID = ESPUI.addControl(ControlType::Number, "Servo position 2 (µseconds):", "1500",  ControlColor::Alizarin, myTab2_ID, &number2Callback);
  ESPUI.addControl(ControlType::Min, "Min-value", ServoMin, ControlColor::None, ServoPos2_ID);
  ESPUI.addControl(ControlType::Max, "Max-value", ServoMax, ControlColor::None, ServoPos2_ID);

  ServoPos3_ID = ESPUI.addControl(ControlType::Number, "Servo position 3 (µseconds):", "1900",  ControlColor::Alizarin, myTab2_ID, &number3Callback);
  ESPUI.addControl(ControlType::Min, "Min-value", ServoMin, ControlColor::None, ServoPos3_ID);
  ESPUI.addControl(ControlType::Max, "Max-value", ServoMax, ControlColor::None, ServoPos3_ID);

  buttonSave_ID       = ESPUI.addControl(ControlType::Button, "Save to Flash ", "Save ",    ControlColor::Peterriver, myTab2_ID, &buttonSaveCallback);
  buttonSetDefault_ID = ESPUI.addControl(ControlType::Button, "Set Default ",   "Default ", ControlColor::Peterriver, myTab2_ID, &buttonSetDefaultCallback);
}


void LoadPreferences() {
  Serial.println("LoadPreferences");
  myPrefInstance.begin(myNameSpace, ReadOnly);

  servoPos1microS = myPrefInstance.getInt    ("ServoPos1"      , 1101);
  servoPos2microS = myPrefInstance.getInt    ("ServoPos2"      , 1501);
  servoPos3microS = myPrefInstance.getInt    ("ServoPos3"      , 1901);

  ESPUI.updateControlValue(ServoPos1_ID, String(servoPos1microS) );
  ESPUI.updateControlValue(ServoPos2_ID, String(servoPos2microS) );
  ESPUI.updateControlValue(ServoPos3_ID, String(servoPos3microS) );

  dbg("LP", servoPos1microS);
  dbg("LP", servoPos2microS);
  dbg("LP", servoPos3microS);
  myPrefInstance.end();
}

void SafePreferences() {
  Serial.println("SafePreferences");

  myPrefInstance.begin(myNameSpace, ReadWrite);
  //myPrefInstance.clear();

  myPrefInstance.putInt    ("ServoPos1"      , servoPos1microS);
  myPrefInstance.putInt    ("ServoPos2"      , servoPos2microS);
  myPrefInstance.putInt    ("ServoPos3"      , servoPos3microS);
  myPrefInstance.end();
  dbg("SP", servoPos1microS);
  dbg("SP", servoPos2microS);
  dbg("SP", servoPos3microS);
  LoadPreferences();
}

void setupServo() {
  myServo.attach(servoPin);
  myServo.setMinimumPulse(700);
  myServo.setMaximumPulse(2300);
  myServo.setSpeed(Speed);
  myServo.write(servoPos2microS);
}

Link is defect.

"biut" → "but"

solved :slightly_smiling_face:

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.