Setting a Static Host ID for ESP32

Hello Everyone, I've seen posts on how to set a Static IP address for an ESP32 on a local network. I am however looking for some guidance on how only to set a static Host ID (last three digits of IP address) for a ESP32, connected to a local network.

My reasoning is as follows. When I connect my ESP32 to a different gateway (in my case a different LTE router) I then have to change the hard coded Static IP so that the Network ID (first three portions of the IP address) matches the gateway's Network ID.

My logic is that if I can set a static Host ID, no matter what gateway the ESP32 is connected to, I can then have a reliable way of determining the ESP32's IP address, simply by knowing the gateway IP (so long as the Host ID is available on the local network).

Note: I would like to do this without changing any router settings I.e. assigning an IP address with a MAC address. Also without mDNS, as I'd like to integrate it with MIT App inventor which I believe does not support mDNS.

My reference code is as follows:

// Set your Static IP address
IPAddress local_IP(192, 168, 1, 184);
// Set your Gateway IP address
IPAddress gateway(192, 168, 1, 1);

IPAddress subnet(255, 255, 0, 0);

void setup() {
  Serial.begin(115200);

  // Configures static IP address
  if (!WiFi.config(local_IP, gateway, subnet) {
    Serial.println("STA Failed to configure");
  }

Please bear with me. I'm not technical and this is my first post.

The usual solution is to have the node get an address assigned via DHCP and then advertise an mDNS name. For example, you can advertise "MyESPServer.local". Then the client can look up the address by name. The actual address doesn't matter and you don't risk collision with another node.

https://espressif.github.io/esp-protocols/mdns/en/index.html

The only way I found that worked was to set the static ip address in the router.

That would have to be configured on each LAN and requires administrator access to the router. The OP wanted to be able to take their ESP32 device to ANY new LAN and use address A.B.C.K, where 'K' is a known constant like '190'. That way their phone could take the phone's LAN address, change the last octet to 'K' and be able to connect to their ESP32 device.

Do you have that working as an example John? I'd love to see it working.

Thanks for the reply John. 100% spot on.
If you can set a static IP address, then I thought surely there's a way to set a static Host ID only.

The client I'm planning to use with MIT App inventor application doesn't seem to support mDNS unfortunately, hence my thinking on a static Host ID.

https://community.appinventor.mit.edu/t/scan-local-network-to-get-the-ip-address/11286

The IP address doesn't really have a "host ID" part. Usually the subnet is defined (especially on home networks) as the first 3 octets xxx.xxx.xxx... then the rest is assigned to each device. But the subnet doesn't always get defined like this, as in your example

192.168.1.100 and 192.168.2.100 are both valid addresses on that network... and therefore you can't assume that the last 3 digits uniquely define a device.

Different networks may have different subnets, so it's not really possible to do what you want. What is unique on one network might not be unique on another.

Are you sure your device doesn't support mDNS?

Look at the article I referenced in Reply #2. It provides example code for setting up an mDNS service, advertising an IP address, advertising services (ports), and querying addresses and ports.

Thanks for the explanation red_car. I'll look into mDNS further.

Thanks John, much appreciated. Will look into this some more.

Thanks John: I started with the mDNS Webserver example in the arduino ide, and added in the code from your reference.
I've posted it below in case it helps others.
I wonder if you could have a look at it for me please as it reports as follows:

.....
Connected to TALK~~~~~~~
IP address: 192.168.1.49
TCP server started
Query A: esp32-mdns.localHost was not found!
Query A: esp32.localHost was not found!
1: Interface: STA, Type: V4
PTR : D-Link DHP-W610AV Configuration Utility
SRV : dlinkap.local:80
AAAA: fe80:0000:0000:0000:7a32:1bff:fec6:dda9
A : 192.168.1.36

New client
Request: /
Sending 200
Done with client

yet it does connect at http://esp32.local/ and give this message: Hello from ESP32 at 192.168.1.49

[code]
/*
  ESP32 mDNS responder sample

  This is an example of an HTTP server that is accessible
  via http://esp32.local URL thanks to mDNS responder.

  Instructions:
  - Update WiFi SSID and password as necessary.
  - Flash the sketch to the ESP32 board
  - Install host software:
    - For Linux, install Avahi (http://avahi.org/).
    - For Windows, install Bonjour (http://www.apple.com/support/bonjour/).
    - For Mac OSX and iOS support is built in through Bonjour already.
  - Point your browser to http://esp32.local, you should see a response.

 */

 /*
  * additional function examples from
  * https://espressif.github.io/esp-protocols/mdns/en/index.html
  */


#include <WiFi.h>
#include <ESPmDNS.h>
#include <WiFiClient.h>

const char* ssid = "TALK~~~~~~";  // Enter SSID here
const char* password = "********";  //Enter Password here

// TCP server at port 80 will respond to HTTP requests
WiFiServer server(80);

//Example method to start mDNS for the STA interface and set hostname and default_instance:

void start_mdns_service()
{
    //initialize mDNS service
    esp_err_t err = mdns_init();
    if (err) {
        printf("MDNS Init failed: %d\n", err);
        return;
    }

    //set hostname
    mdns_hostname_set("esp32"); //changed from my-esp32 to esp32
    //set default instance
    mdns_instance_name_set("John's ESP32 mDNSThing");
}

//Example method to add a few services and different properties:
void add_mdns_services()
{
    //add our services
    mdns_service_add(NULL, "_http", "_tcp", 80, NULL, 0);
    mdns_service_add(NULL, "_arduino", "_tcp", 3232, NULL, 0);
    mdns_service_add(NULL, "_myservice", "_udp", 1234, NULL, 0);

    //NOTE: services must be added before their properties can be set
    //use custom instance for the web server
    mdns_service_instance_name_set("_http", "_tcp", "John's ESP32 Web Server");

    mdns_txt_item_t serviceTxtData[3] = {
        {"board","{esp32}"},
        {"u","user"},
        {"p","password"}
    };
    //set txt data for service (will free and replace current data)
    mdns_service_txt_set("_http", "_tcp", serviceTxtData, 3);

    //change service port
    mdns_service_port_set("_myservice", "_udp", 4321);
}


//Example method to resolve host IPs:
void resolve_mdns_host(const char * host_name)
{
    printf("Query A: %s.local", host_name);

    struct ip4_addr addr;
    addr.addr = 0;

    esp_err_t err = mdns_query_a(host_name, 2000,  &addr);
    if(err){
        if(err == ESP_ERR_NOT_FOUND){
            printf("Host was not found!\n");
            return;
        }
        printf("Query Failed");
        return;
    }

    printf(IPSTR, IP2STR(&addr));
}

//Example method to resolve local services:
static const char * if_str[] = {"STA", "AP", "ETH", "MAX"};
static const char * ip_protocol_str[] = {"V4", "V6", "MAX"};

void mdns_print_results(mdns_result_t * results){
    mdns_result_t * r = results;
    mdns_ip_addr_t * a = NULL;
    int i = 1, t;
    while(r){
        printf("%d: Interface: %s, Type: %s\n", i++, if_str[r->tcpip_if], ip_protocol_str[r->ip_protocol]);
        if(r->instance_name){
            printf("  PTR : %s\n", r->instance_name);
        }
        if(r->hostname){
            printf("  SRV : %s.local:%u\n", r->hostname, r->port);
        }
        if(r->txt_count){
            printf("  TXT : [%u] ", r->txt_count);
            for(t=0; t<r->txt_count; t++){
                printf("%s=%s; ", r->txt[t].key, r->txt[t].value);
            }
            printf("\n");
        }
        a = r->addr;
        while(a){
            if(a->addr.type == IPADDR_TYPE_V6){
                printf("  AAAA: " IPV6STR "\n", IPV62STR(a->addr.u_addr.ip6));
            } else {
                printf("  A   : " IPSTR "\n", IP2STR(&(a->addr.u_addr.ip4)));
            }
            a = a->next;
        }
        r = r->next;
    }

}

void find_mdns_service(const char * service_name, const char * proto)
{
    ESP_LOGI(TAG, "Query PTR: %s.%s.local", service_name, proto);

    mdns_result_t * results = NULL;
    esp_err_t err = mdns_query_ptr(service_name, proto, 3000, 20,  &results);
    if(err){
        ESP_LOGE(TAG, "Query Failed");
        return;
    }
    if(!results){
        ESP_LOGW(TAG, "No results found!");
        return;
    }

    mdns_print_results(results);
    mdns_query_results_free(results);
}

//Example of using the methods above:
void my_app_some_method(){
    //search for esp32-mdns.local
    resolve_mdns_host("esp32-mdns");
    //search for esp32.local
    resolve_mdns_host("esp32");

    //search for HTTP servers
    find_mdns_service("_http", "_tcp");
    //or file servers
    find_mdns_service("_smb", "_tcp"); //windows sharing
    find_mdns_service("_afpovertcp", "_tcp"); //apple sharing
    find_mdns_service("_nfs", "_tcp"); //NFS server
    find_mdns_service("_ftp", "_tcp"); //FTP server
    //or networked printer
    find_mdns_service("_printer", "_tcp");
    find_mdns_service("_ipp", "_tcp");
}

void setup(void)
{  
    Serial.begin(115200);

    // Connect to WiFi network
    WiFi.begin(ssid, password);
    Serial.println("");

    // Wait for connection
    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }
    Serial.println("");
    Serial.print("Connected to ");
    Serial.println(ssid);
    Serial.print("IP address: ");
    Serial.println(WiFi.localIP());
/*
    // Set up mDNS responder:
    // - first argument is the domain name, in this example
    //   the fully-qualified domain name is "esp32.local"
    // - second argument is the IP address to advertise
    //   we send our IP address on the WiFi network
    if (!MDNS.begin("esp32")) {
        Serial.println("Error setting up MDNS responder!");
        while(1) {
            delay(1000);
        }
    }
    Serial.println("mDNS responder started");
*/

//Example method to start mDNS for the STA interface and set hostname and default_instance:
    start_mdns_service();
    
    // Start TCP (HTTP) server
    server.begin();
    Serial.println("TCP server started");

    // Add service to MDNS-SD
    //MDNS.addService("http", "tcp", 80);

    add_mdns_services();

    my_app_some_method();
}

void loop(void)
{
    // Check if a client has connected
    WiFiClient client = server.available();
    if (!client) {
        return;
    }
    Serial.println("");
    Serial.println("New client");

    // Wait for data from client to become available
    while(client.connected() && !client.available()){
        delay(1);
    }

    // Read the first line of HTTP request
    String req = client.readStringUntil('\r');

    // First line of HTTP request looks like "GET /path HTTP/1.1"
    // Retrieve the "/path" part by finding the spaces
    int addr_start = req.indexOf(' ');
    int addr_end = req.indexOf(' ', addr_start + 1);
    if (addr_start == -1 || addr_end == -1) {
        Serial.print("Invalid request: ");
        Serial.println(req);
        return;
    }
    req = req.substring(addr_start + 1, addr_end);
    Serial.print("Request: ");
    Serial.println(req);

    String s;
    if (req == "/")
    {
        IPAddress ip = WiFi.localIP();
        String ipStr = String(ip[0]) + '.' + String(ip[1]) + '.' + String(ip[2]) + '.' + String(ip[3]);
        s = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<!DOCTYPE HTML>\r\n<html>Hello from ESP32 at ";
        s += ipStr;
        s += "</html>\r\n\r\n";
        Serial.println("Sending 200");
    }
    else
    {
        s = "HTTP/1.1 404 Not Found\r\n\r\n";
        Serial.println("Sending 404");
    }
    client.print(s);

    client.stop();
    Serial.println("Done with client");
}

[/code]

Is that one sketch that is both client and server? You would typically run mDNS on the server and query for the server's address from the client.

Hi John, I understood this example to be an "mDNS server" that I can access by name - so I dont need it to have a fixed ip address;

I can access it on my local network as http://esp32.local and get a response - so that works.

(I dont have bonjour installed - dont know what difference that would make, and I dont want to install iTunes)

I've added all the example routines from your link in the hope that with a working example I may receive some enlightenment as to what it all does.

I dont understand why it cant find

//search for esp32.local
    resolve_mdns_host("esp32");

when it shows on the network.
image

and ..
having installed "network service discovery" on my android phone it finds "John's ESP32 web server"; and when I access it I see the "hello" message.

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