ESP8266 Client Problems POSTing to Azure Web API 2.0 service

Having observed the admiration that @ Justin received for his molecules, especially the Neon one, I lashed an ESP8266 esp-12 with V1 firmware to a home-grown board running the default Cerberus 4.3.1 firmware. After a little time and head scratching I was able to connect the client to my WiFi network and POST to an Azure hosted WEB API 2.0 site. The posted message was based on the following class:


public class Temperature
{
    public int Id { get; set; }
    public string Value { get; set; }
    public string DeviceId { get; set; }
    public string Count { get; set; }
    public DateTime CreatedDate { get; set; }
}

The CreatedDate is not sent from the NETMF device, but it updated in the API Method on Azure. I added a count so that I could track the number of messages sent versus the number that where actually successfully written to an Azure hosted SQL DB.

When it works well, it really works well. However, there is occasionally an exception raised in mscorlib.dll when seems to affect the http header string and as such the send fails. For this error I usually get an Http 400 (badly formed header) or 404 (page not found) error. Sometime however, other things trip me up such as the connection not being made, etc.

I loop through the connect to AP code and then call


AT+CIPJAP?

to check the status, only advancing once itā€™s connected.

I also place


AT+CIPSTART=TCP, url, port

in a loop to ensure the connection is established before calling


AT+CIPSEND=message_length

and then sending the actual message.

The returned messages from the ESP8266 or the web help but sometimes it can day several hours before it fails.

Does anyone have any or know of any client code that might help me create a more robust client solution which improves my yield of successful post from approximately 97% to 99.999% (100% seemed to be asking too much? :smiley:

Many thanks in advance.

3 Likes

@ Jason - Could you post the code?

@ munderhill - Itā€™s not pretty, but when everything is well behaved it posted several thousand JSON web service requests, one every 5 seconds, without a problem. It uses SimpleSerial from @ Iggmoe to handle the UART stuff. and some code from @ Justin for a couple of other things.


public enum ESPCommand
{
    None,
    Reset,
    FWVersion,
    WifiMode,
    JoinAP,
    ConnectedAP,
    IPStatus,
    IPStart,
    IPSend,
    IPClose
}

public class Program
{
    private static SimpleSerial serial;
    static string[] dataIn;
    static string delimiter = string.Empty;
    private static string cmd, getStr;
    private static Random rnd;
    private static string deviceId = "ESP8266_1";
    private static long count = 0;
    private static bool apAttached = false;
    private static bool ipConnected = false;
    private static ESPCommand espCommand = ESPCommand.None;
    private static string response;
    private static bool sendFailed = false;

    public static void Main()
    {
        Debug.Print("WiFi Remote Switch...\r\n");
        Thread.Sleep(1000);
            
        serial = new SimpleSerial("COM2", 115200);
        serial.DataReceived += serial_DataReceived;
        serial.Open();

        SetUp();

        ThreadStart ts = new ThreadStart(JsonPost);
        Thread t = new Thread(ts);
        t.Start();
            
        Thread.Sleep(Timeout.Infinite);
    }

    static void serial_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
    {
        dataIn = delimiter != string.Empty ? serial.Deserialize(delimiter) : serial.Deserialize();
        for (int index = 0; index < dataIn.Length; index++)
        {
            response = dataIn[index];
            Debug.Print(_response);

            if (response == "SEND FAIL")
            {
                sendFailed = true;
                count--;
            }
            else if(response == "ERROR")
            {
                sendFailed = true;
                count--;
            }

            switch (espCommand)
            {
                case ESPCommand.ConnectedAP:
                    {
                        if(response == "OK")
                            apAttached = true;
                        break;
                    }
                case ESPCommand.IPStatus:
                    {
                        if(response.IndexOf("STATUS", 0) == 0)
                        {
                            string[] result = response.Split(':');
                            if (result[1] == "3")
                                ipConnected = true;
                            else
                                ipConnected = false;
                        }

                        break;
                    }
            }
        }
    }
        
    public static void SendString(string data, bool newLine = true)
    {
        if (newLine)
        {
            serial.WriteLine(data);
        }
        else
        {
            serial.Write(data + "\n");
        }
    }
        
    static void SetUp()
    {
        espCommand = ESPCommand.FWVersion;
        SendString("AT+GMR");
        Thread.Sleep(100);

        espCommand = ESPCommand.Reset;
        SendString("AT+RST");
        Thread.Sleep(100);

        espCommand = ESPCommand.WifiMode;
        SendString("AT+CWMODE=3");
        Thread.Sleep(100);

        apAttached = false;
        do
        {
            espCommand = ESPCommand.JoinAP;
            SendString("AT+CWJAP=\"BTHub3-5KZ9\",\"46d24f5ef6\"\r\n");
            Thread.Sleep(5000);

            espCommand = ESPCommand.ConnectedAP;
            SendString("AT+CIPJAP?");
            Thread.Sleep(100);
        } while (apAttached == false);

    }

    private static void JsonPost)
    {
        // Using StringBuilder to see if that eliminates the mscorlib.dll exception
        //StringBuilder header = new StringBuilder();
            
        //header.Append("POST /api/json HTTP/1.1\r\n");
        ////header.Append("Accept: application/json, text/javascript, */*; q=0.01\r\n");
        //header.Append("Content-Type: application/x-www-form-urlencoded; charset=UTF-8\r\n");
        ////header.Append("X-Requested-With: XMLHttpRequest\r\n");
        ////header.Append("Accept-Language: en-GB,en;q=0.8,de-DE;q=0.5,de;q=0.3\r\n");
        ////header.Append("Accept-Encoding: gzip, deflate\r\n");
        //header.Append("Host: www.jasonjames.co.uk\r\n");
        //////header.Append("Host: 192.168.1.65\r\n");
        ////header.Append("DNT: 1\r\n");
        //header.Append("Connection: Close\r\n");
        ////header.Append("Pragma: no-cache\r\n");
        // It didn't...

        string header = "POST /api/json HTTP/1.1\r\nContent-Type: application/x-www-form-urlencoded; charset=UTF-8\r\nHost: www.jasonjames.co.uk\r\nConnection: Close\r\n";
        rnd = new Random();

        for(;;)
        {
            ipConnected = false;
            do
            {
                cmd = "AT+CIPSTART=\"TCP\",\"";
                //_cmd += "192.168.1.65";
                cmd += "www.jasonjames.co.uk";
                //_cmd += "\",54275";
                cmd += "\",80";

                espCommand = ESPCommand.IPStart;
                SendString(cmd);
                Thread.Sleep(500); // 500

                espCommand = ESPCommand.IPStatus;
                SendString("AT+CIPSTATUS");
                Thread.Sleep(250);
            } while (ipConnected == false);

                
            double r = rnd.NextDouble() * 100;


            // Format to string sent to JSON Web API
            //Value=100&DeviceId=kettle&Count=1
            string dataString = "Value=" + r.ToString("F2") + "&DeviceId=C3PO&Count=" + count.ToString();
            int dataLength = dataString.Length;

            String message = header; // header.ToString();
            message += "Content-Length: " + dataLength.ToString();
            message += "\r\n\r\n";
            message += dataString;
            int totalLength = message.Length;

            cmd = "AT+CIPSEND=";
            cmd += totalLength;

            espCommand = ESPCommand.IPSend;
            SendString(cmd);
            Thread.Sleep(250); // 500

            sendFailed = false;
            SendString(message);

            count++;

            // Might not need to close the connection
            //espCommand = ESPCommand.IPClose;
            // SendString("AT+CIPCLOSE");
            // Thread.Sleep(1000);
            //Debug.Print(r.ToString());
            Thread.Sleep(2000); // 5000

            if (sendFailed)
                SetUp();

        }
    }
}

There are some comments, but as with all WIP they are a little few and far between. I tried using the StringBuilder class to eliminate the exception, and that code is still there, just commented out.

I welcome your thoughts.

2 Likes

@ Jason - The only thing that I might recommend trying is when the AT+CIPSEND command is sent, the manual recommends that you wait for the ā€œ>ā€ to be returned before sending the actual data. As a side note, my driver does not work 100% either, I have been able to achieve a 98% success rate over 32K web service calls.

2 Likes

@ munderhill - Iā€™ll give it a go and post back. Given your 98% success rate, how do you cope with retries?

@ Jason - I fire an Error event when it occurs and then manually retry.

1 Like

Hmm, we should be coding our own firmware for the ESP8266 :wink:

@ njbuch - Not sure if that was a statement or a question!

@ Jason - I was hoping for someone with experience with the ESP8266 to comment on it, and get some feedback that could enlighten me. I guess its pretty complicated to build the firmware with a long toolchain, but I might be positively surprisedā€¦??

@ njbuch - The crazy Moroccan is already building itā€¦

3 Likes

@ Bill Gates - Any idea what the new FW will have that isnā€™t already supported? My issue is/was the netmf code to handle errors and exceptions, not what was going on on the ESP.

Iā€™m curious to understand what is being changed or improved.

@ Jason - You will have to ask my Padawan once he returns from his afternoon Casablancian siesta

2 Likes

@ Jason - If I remember correctly, his mod had to do with joining a UDP multicast group. See https://www.ghielectronics.com/community/forum/topic?id=18818

1 Like

@ munderhill - I struggled catching the > but got the ā€˜OKā€™ so that helped. Thanks.

However, the biggest issue I Iā€™ve got is an exception in mscorlib.dll. Iā€™m struggling to handle it (or better yet prevent it in the first place) because I canā€™t figure out where itā€™s being raised. Iā€™ve got some tryf blocks in place but still nothing obvious. The problem seems to be that when the exception occurs, my header gets scrambled and 99 times out of a 100 the URL gets changed and I receive a 404 error :wall:

Any thoughts?

@ Jason, Handle the 404 ?

1 Like

@ Jason - What kind of exception are you getting?

1 Like

@ munderhill - Hereā€™s whatā€™s being sent


===========================================================================================================================================
===========================================================================================================================================
POST /api/json HTTP/1.1
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Host: www.jasonjames.co.uk
Connection: Close
Content-Length: 33

Value=77.07&DeviceId=C3PO&Count=7
===========================================================================================================================================
===========================================================================================================================================

and hereā€™s the output window:


AT+CIPSEND=191
OK
> POST /api/json HTTP/1.1
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
A first chance exception of type 'System.Exception' occurred in mscorlib.dll
Host: www.jasonjamk
Connection: Close
Content-Length: 33
Value=77.07&DeviceId=C3PO&Count=7
busy s...
SEND OK
+IPD,1412:HTTP/1.1 404 Site Not Found
Content-Type: text/html
Server: Microsoft-IIS/8.0
Date: Tue, 07 Apr 2015 20:24:22 GMT
Connection: close
Content-Length: 5160
<!DOCTYPE html>
<html>
<head>
    <title>Microsoft Azure Web Site - Error 404</title>
    <style type="text/css">
        html {
            height: 100%;
            width: 100%;
        }
        #feature {
            width: 960px;
            margin: 75px auto 0 auto;
            overflow: auto;
        }
        #content {
            font-family: "Segoe UI";
            font-weight: normal;
            font-size: 22px;
            color: #ffffff;
            float: left;
            width: 460px;
            margin-top: 68px;
            margin-left: 0px;
            vertical-align: middle;
        }
            #content h1 {
                font-family: "Segoe UI Light";
                color: #ffffff;
                font-weight: normal;
                font-size: 60px;
                line-height: 48pt;
                width: 800px;
            }
        p a, p a:visited, p a:active, p a:hover {
            color: #ffffff;
        }
        #content a.button {
            background: #0DBCF2;
            border: 1px solid #FFFFFF;
            color: #FFFFFF;
            display: inline-block;
            font-family: Segoe UI;
            font-size: 24px;
            lin
+IPD,1412:e-height: 46px;
            margin-top: 10px;
            padding: 0 15px 3px;
            text-decoration: none;
        }
            #content a.button img {
                float: right;
                padding: 10px 0 0 15px;
            }
            #content a.button:hover {
                background: #1C75BC;
            }        
    </style>
    <script type="text/javascript">
        function toggle_visibility(id) {
            var e = document.getElementById(id);
            if (e.style.display == 'block')
                e.style.display = 'none';
            else
                e.style.display = 'block';
        }
    </script>
</head>
<body bgcolor="#00abec">
    <div id="feature">
        <div id="content">
            <h1>Error 404 - Web Site not found!</h1>
            <p>The website you have attempted to reach is not available in this Microsoft Azure Web Sites region. This could be due to one of several reasons:
            <p>
                1. The web site owner has registered a custom domain to point to the Microsoft Azure Web Site, but has not yet configured Azure to recognize it. <a href="#" onclick="toggle_visibility('moreone');">Click here to read more</a></abbr>.
                <div id="moreone" style="display:none">
                    <font size=2>
                        When a site owner wants to use a custom domain with 
+IPD,1412:a <a href="http://www.windowsazure.com/en-us/services/web-sites/">Microsoft Azure Web Sites</a> website, Azure needs to be configured to recognize the custom domain name, so that it can route the request to the appropriate server in the region. After registering the domain with a domain provider and configuring a DNS CNAME record to point to the site&#39;s Azurewebsites.net address (for example, contoso.azurewebsites.net), the website owner also needs to go to the Azure Portal and configure the site for the new domain. <a href="http://www.windowsazure.com/en-us/documentation/articles/web-sites-custom-domain-name/">Click here</a> to learn more about configuring the custom domains for a web site.
                     </font>
</div>
        <p>
            2. The web site owner has moved the web site to a different region, but the DNS cache is still directing to the old IP Address that was used in the previous region. <a href="#" onclick="toggle_visibility('moretwo');">Click here to read more.</a>
            <div id="moretwo" style="display:none">
                <font size=2>
A first chance exception of type 'System.Exception' occurred in mscorlib.dll
                    With <a href="http://www.windowsazure.com/en-us/services/web-sites/">Microsoft Azure Web Sites</a>, the site is stored in a datacenter located in the region that the web site owner has selected when creating the site, and  server resolves the website address that was chosen for it 
+IPD,1085:to that datacenter. DNS servers are in charge of resolving the name of the server the user is trying to reach into an IP address, but clients cache this information in order to be able to load the page as fast as possible. If this site was deleted and re-created in another region, the new site will have a different IP address, but the client might still be caching the old IP address. First, try clearing the cache on your client <a href="http://technet.microsoft.com/en-us/library/cc781949(v=ws.10).aspx">as described here</a>. If this does not help, then this is probably due to the caching done on an intermediate DNS server such as the one used by your Internet Service Provider. If so, this issue should clear up soon, once the DNS cache reaches its time-to-live period. Please try to visit the site again in approximately one hour.  If you continue to receive this error page, please contact <a href="http://www.windowsazure.com/en-us/support/options/">Microsoft support</a>.
                    </font>
            </div>
        </div>
     </div>
</body>
</html>
CLOSED

As you can see the Host: entry has been changed and just before that thereā€™s an exception:

A first chance exception of type ā€˜System.Exceptionā€™ occurred in mscorlib.dll

@ PiWi - Doable, but Iā€™d rather figure out why itā€™s there in the first place, or at least code around it to increase the success rate of the sends.

1 Like

iā€™m back from taking my late afternoon nap as Mr @ Bill suggested, if he only knew how I still get paid while taking my naps :whistle:

please Jason replace the SimpleSerial.cs file with this one: and read the below code on how to properly use it to reply to client requestsā€¦

SimpleSerial.cs


 //Source for SimpleSerial taken from IggMoe's SimpleSerial Class https://www.ghielectronics.com/community/codeshare/entry/644
  
using System;
using System.Diagnostics;
using System.IO.Ports;
using System.Text;
using System.Threading;
using Microsoft.SPOT;

namespace ESP8266Wifi
{


    /// <summary>
    ///     Extends the .NET Micro Framework SerialPort Class with additional methods from the
    ///     Full .NET Framework SerialPort Class as well as other useful methods.
    /// </summary>
    public class SimpleSerial : SerialPort
    {
        private string _remainder;

        internal SimpleSerial(string portName, int baudRate)
            : base(portName, baudRate, Parity.None, 8, StopBits.One)
        {
            DiscardInBuffer();
            DiscardOutBuffer();
        }

        /// <summary>
        ///     Stores any incomplete message that hasn't yet been terminated with a delimiter.
        ///     This will be concatenated with new data from the next DataReceived event to (hopefully) form a complete message.
        ///     This property is only populated after the Deserialize() method has been called.
        /// </summary>
        internal string Remainder
        {
            get { return _remainder; }
        }


        /// <summary>
        ///     Writes the specified string to the serial port.
        /// </summary>
        /// <param name="txt" />
        internal void Write(string txt)
        {
            base.Write(Encoding.UTF8.GetBytes(txt), 0, txt.Length);
        }

        /// <summary>
        ///     Writes the specified string and the NewLine value to the output buffer.
        /// </summary>
        internal void WriteLine(string txt)
        {
            Write(txt + "\r\n");
        }

        /// <summary>
        ///     Reads all immediately available bytes, as binary data, in both the stream and the input buffer of the SerialPort
        ///     object.
        /// </summary>
        /// <returns>
        ///    System.Byte[]
        /// </returns>
        internal byte[] ReadExistingBinary()
        {
            var arraySize = BytesToRead;
            var received = new byte[arraySize];
            var count = Read(received, 0, arraySize);

            //   Debug.Print("*******Count:" + i + " Bytead=" + BytesToRead);
            if (count > 0)
                return received;
            return new byte[] { 32 };
        }

  

        internal string ReadExisting()
        {
            var data= ReadExistingBinary();
            var t = new char[data.Length];
     
            for (int i = 0; i < data.Length; i++)
            {
                t[i] = (char)data[i];
            }  
            
          
            try
            {
              
                return new string(t);

                           }
            catch (Exception ex)
            {
                Debug.Print("Error" + ex.Message);
                return String.Empty;//"Error\r\n";//
            }
        }
      
        /// <summary>
        ///     Opens a new serial port connection.
        /// </summary>
        internal new void Open()
        {
            _remainder = String.Empty;
            base.Open();
        }

        /// <summary>
        ///     Splits data from a serial buffer into separate messages, provided that each message is delimited by one or more
        ///     end-of-line character(s).
        /// </summary>
        /// <param name="delimiter">Character sequence that terminates a message line. Default is "\r\n".</param>
        /// <param name="includeDelimiterInOutput"></param>
        /// <returns>
        ///     An array of strings whose items correspond to individual messages, without the delimiters.
        ///     Only complete, properly terminated messages are included. Incomplete message fragments are saved to be appended to
        ///     the next received data.
        ///     If no complete messages are found in the serial buffer, the output array will be empty with Length = 0.
        /// </returns>
        internal string[] Deserialize(string delimiter = "\r\n", bool includeDelimiterInOutput = false, bool findfrw = false)
        {
            
            return ReadExisting().Split(delimiter.ToCharArray());
        }

        #endregion



    }
}

and you would use it as follow:


 //private const UInt16 _autoResetWaitTime = 20000;
  public static AutoResetEvent SerialBlocking = null;
  public static SimpleSerial MySerialPort;

        public delegate void DataProcessorHandler(string rawdata, SimpleSerial port);//SerialPort

        public static event DataProcessorHandler DataProcessor;
        // The method which fires the Event
        protected static void OnDataProcessor(string rawdata, SimpleSerial port)//SerialPort
        {

            // Check if there are any Subscribers
            if (DataProcessor != null)
            {
                // Call the Event
                DataProcessor(rawdata, port);
            }
        }

  public static void NewProcess(string rawData, SimpleSerial sp)
        {
          
            switch (rawData)
            {
                case ">":
                    {

                        // Debug.Print("**************************Serve the page**************************");

                        //checkHttpRequest = false;

                        var strr = "<html><head><title>Welcome</title></head><body><p>Welcome " + "Pages Requested" +
                                   "=" + _pageCounter
                                   + " Pages Served=" + ++_pagesServed + " RebootCounter=" + _rebootCounter +
                                   " ChannelId=" + _channelId + ".</p></body></html>";

                        var headersr = "HTTP/1.1 200 OK\r\nContent-Type: " + "text/html" + "\r\nContent-Length: " +
                                       strr.Length + "\r\nServer: " + "hostname" +
                                       "\r\nCache-Control: no-cache\r\nConnection: keep-alive\r\n\r\n"; //
                        var cmd = Encoding.UTF8.GetBytes(headersr + strr);
                        lock (sp)
                        {
                            sp.Write(cmd, 0, cmd.Length);
                        }
                    }
                    break;
                case "ready":
                    Debug.Print("Ready Found");
                    if (SerialBlocking != null) SerialBlocking.Set();
                    break;
                case "OK":
                  //  Debug.Print("OK FOUND");
                    if (SerialBlocking != null) SerialBlocking.Set();
                    break;
                default:
                    {
                        if (rawData.Length > 5)
                        {

                            if (rawData.Substring(0, 4) == "+IPD")
                            {

                                // if (sentence.Length > 5)
                                //  {
                                _channelId = Int32.Parse(rawData.Substring(5, 1));
                                //  }
                                //  else
                                //  {
                                //       Debug.Print("No channel found=" + sentence + "=" + sentence.IndexOf("+IPD") + "=" + sentence.Length);
                                //  }

                                // var strr = Resources.GetString(Resources.StringResources.index);
                                var strr = "<html><head><title>Welcome</title></head><body><p>Welcome " +
                                           "Pages Requested" + "=" + _pageCounter++
                                           + " Pages Served=" + _pagesServed + " RebootCounter=" + _rebootCounter +
                                           " ChannelId=" + _channelId + ".</p></body></html>";
                                var headersr = "HTTP/1.1 200 OK\r\nContent-Type: " + "text/html" +
                                               "\r\nContent-Length: " +
                                               strr.Length + "\r\nServer: " + "hostname" +
                                               "\r\nCache-Control: no-cache\r\nConnection: keep-alive\r\n\r\n"; //
                                //Thread.Sleep(1);
                                var cmd =
                                    Encoding.UTF8.GetBytes("AT+CIPSEND=" + _channelId + "," +
                                                           (int)(headersr.Length + strr.Length) +
                                                           "\r\n");
                                //checkHttpRequest = true;
                                lock (sp)
                                {
                                    sp.Write(cmd, 0, cmd.Length);
                                    //Esp.Flush();
                                }
                            }
                        }
                        break;
                    }
            }
            //  }
            // }
            // MyProcTimer.Stop();
        }



     public static void Main()
        {


            Debug.Print("Serial Port Count is: " + SerialPortCount);
            DataProcessor += NewProcess;
            SerialBlocking = new AutoResetEvent(false);
            MySerialPort = new SimpleSerial("COM2", 115200);
            MySerialPort.Open();
            MySerialPort.DataReceived += MySerialPort_DataReceived;
new Thread(() => TestEsp(MySerialPort)).Start();
           //keep the program running
            Thread.Sleep(Timeout.Infinite);
}

        private static void MySerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {

            if (e.EventType == SerialData.Chars)
            {
     
                // Cast the event source as a SimpleSerial object
                var sp = sender as SimpleSerial;

                // Extract an array of complete sentences from the port.
                // Only complete, properly terminated sentences are included in this array.

                if (sp != null)
                {
                    var sentences = sp.Deserialize("");//this is important to not look for any delimiter must be an empty string we don't want it to terminate at \r\n to be able to catch the >
                    Thread.Sleep(1);//important to have this sleep or you will miss data from the serial port.
                    // Pull each sentence from the array and perform further processing
                    for (var index = 0; index < sentences.Length; index++)
                    {
             
                        //Debug.Print("Got:" + sentences[index]);
                        OnDataProcessor(sentences[index], sp);
}
}
}
}

        public static void TestEsp(SerialPort Esp)
        {

            Debug.Print("TestEsp Started");
            if (SerialBlocking == null) SerialBlocking = new AutoResetEvent(false);

            // SerialBlocking.Reset();
            var cmd = Encoding.UTF8.GetBytes("AT\r\n");
            Esp.Write(cmd, 0, cmd.Length);
            // Wait for the command to be completed
            SerialBlocking.WaitOne();//_autoResetWaitTime, true);

            //resets the module only during first boot.

            if (!_softRest)
            {
                // Debug.Print("Reset");
                _softRest = true;
                // SerialBlocking.Reset();
                cmd = Encoding.UTF8.GetBytes("AT+RST\r\n");
                Esp.Write(cmd, 0, cmd.Length);
                // Wait for the command to be completed
                SerialBlocking.WaitOne(); //AT+RST Returns OK immediately
                //wait for the reset to return ready
                SerialBlocking.WaitOne();
            }
            // Debug.Print("Done Reset");
            //Thread.Sleep(100);

            // Query firmware version
            //cmd = Encoding.UTF8.GetBytes("AT+GMR\r\n");
            //Esp.Write(cmd, 0, cmd.Length);

            //// Wait for the command to be completed
            //SerialBlocking.WaitOne();

            //Thread.Sleep(100);
            //  SerialBlocking.Reset();
            // Set wifi mode 3 = Client and Soft AP
            cmd = Encoding.UTF8.GetBytes("AT+CWMODE=3\r\n");
            Esp.Write(cmd, 0, cmd.Length);
            // Wait for the command to be completed
            SerialBlocking.WaitOne();//_autoResetWaitTime, true);

            //  SerialBlocking.Reset();
            // Set the Soft AP
            cmd = Encoding.UTF8.GetBytes("AT+CWSAP=\"COOLAP2\",\"21030826\",5,0\r\n");
            Esp.Write(cmd, 0, cmd.Length);

            // Wait for the command to be completed
            SerialBlocking.WaitOne();//_autoResetWaitTime, true);

            //  SerialBlocking.Reset();
            // AT+CWLAP = List access points
            cmd = Encoding.UTF8.GetBytes("AT+CWLAP\r\n");
            Esp.Write(cmd, 0, cmd.Length);

            // Wait for the command to be completed
            SerialBlocking.WaitOne();//_autoResetWaitTime, true);

            while (true)
            {
                //Thread.Sleep(100);
                //       SerialBlocking.Reset();
                // Join an access point
                cmd = Encoding.UTF8.GetBytes("AT+CWJAP=\"" + Apssid + "\",\"" + Password + "\"\r\n");
                Esp.Write(cmd, 0, cmd.Length);

                // Wait for the command to be completed
                if (SerialBlocking.WaitOne())//_autoResetWaitTime, true))
                    break;
            }
            //Thread.Sleep(100);
            //    SerialBlocking.Reset();
            // Show IP address
            cmd = Encoding.UTF8.GetBytes("AT+CIFSR\r\n");
            Esp.Write(cmd, 0, cmd.Length);

            // Wait for the command to be completed
            SerialBlocking.WaitOne();//_autoResetWaitTime, true);

            // Thread.Sleep(100);
            //     SerialBlocking.Reset();
            //change it to multiple mode connection required to start a server
            cmd = Encoding.UTF8.GetBytes("AT+CIPMUX=1\r\n");
            Esp.Write(cmd, 0, cmd.Length);
            // Wait for the command to be completed
            SerialBlocking.WaitOne();//_autoResetWaitTime, true);

            //Thread.Sleep(100);
            //     SerialBlocking.Reset();
            // Start the server port 80
            cmd = Encoding.UTF8.GetBytes("AT+CIPSERVER=1,80\r\n");
            Esp.Write(cmd, 0, cmd.Length);
            // Wait for the command to be completed
            SerialBlocking.WaitOne();//_autoResetWaitTime, true);

            //Thread.Sleep(100);
            //      SerialBlocking.Reset();
            //set timeout
            cmd = Encoding.UTF8.GetBytes("AT+CIPSTO=20\r\n");
            Esp.Write(cmd, 0, cmd.Length);
            //  Wait for the command to be completed
            SerialBlocking.WaitOne();//_autoResetWaitTime, true);
_softRest = false;
}


Cheers,
Jay

1 Like

@ Jay Jay - Thanks for the code. My application is a client trying to post for a server, whilst yours in a server accepting multiple clients. Iā€™ll take what youā€™ve posted and see what \I can do to convert it to client code instead.

Iā€™ve not used AutoRestartEvents before so that will be interesting

Iā€™ll post an update later.