[
  {
    "path": ".gitignore",
    "content": "# Compiled Object files\n*.slo\n*.lo\n*.o\n*.obj\n\n# Precompiled Headers\n*.gch\n*.pch\n\n# Compiled Dynamic libraries\n*.so\n*.dylib\n*.dll\n\n# Fortran module files\n*.mod\n\n# Compiled Static libraries\n*.lai\n*.la\n*.a\n*.lib\n\n# Executables\n*.exe\n*.out\n*.app\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2015 ekstrand\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n\n"
  },
  {
    "path": "README.md",
    "content": "# SerialESP8266wifi\nA simple ESP8266 Arduino library with built in re-connect functionality.\n* The ESP8266 is a dirtcheap wifimodule. I got mine for about 2.50 US including shipping at Aliexpress. Read about it here: https://nurdspace.nl/ESP8266\n* An AT command reference can be found here: https://github.com/espressif/esp8266_at/wiki/AT_Description\n* Contact me if you have ideas for changes or new features, found a bug or just want to buy a beer at jonas[AT]inspirativ[DOT]se\n\n## Memory footprint and more\n* Tested on an Arduino Nano v3 ATMega 328, Arduino IDE 1.60, ESP8266 module with firmware version 0.9.2.4\n* approx 3.5kB of program storage\n* approx 285 bytes or RAM\n\n\n## Install\n* Download the library as a zip from https://github.com/ekstrand/SerialESP8266wifi/archive/master.zip \n* Unzip and place in ARDUINO_HOME/libraries/ directory as SerialESP8266wifi\n* Restart the Arduino IDE\n* In your sketch do a `#include <SerialESP8266wifi.h>`\n* To set up a simple server for testing, I like to use SocketTest http://sourceforge.net/projects/sockettest/\n\n## Constructor\n\n**SerialESP8266wifi(Stream serialIn, Stream serialOut, byte resetPin)**\n* **serialIn** this object is used to read from the ESP8266, you can use either hardware or software serial\n* **serialOut** this object is used to write to the ESP8266, you can use either hardware or software serial\n* **resetPin** this pin will be pulled low then high to reset the ESP8266. It is assumed that a the CH_PD pin is connected the this pin. See pin out and more at: http://www.electrodragon.com/w/ESP8266#Module_Pin_Description\n* **Example:** ```SerialESP8266wifi wifi(swSerial, swSerial, 10);```\n\n**SerialESP8266wifi(Stream serialIn, Stream serialOut, byte resetPin, Stream debugSerial)**\n* **serialIn** this object is used to read from the ESP8266, you can use either hardware or software serial\n* **serialOut** this object is used to write to the ESP8266, you can use either hardware or software serial\n* **resetPin** this pin will be pulled low then high to reset the ESP8266. It is assumed that a the CH_PD pin is connected the this pin. See pin out and more at: http://www.electrodragon.com/w/\nESP8266#Module_Pin_Description\n* **debugSerial** enables wifi debug and local echo to Serial (could be hw or sw)\n* **Example:** ```SerialESP8266wifi wifi(swSerial, swSerial, 10, Serial);```\n\n\n## Starting the module\n**boolean begin()** calling this method will do a hw reset on the ESP8266 and set basic parameters\n* **return** will return a true or false depending if the module was properly initiated\n* **Example:** `boolean esp8266started = wifi.begin();`\n\n## Connecting to an access point\n**boolean connectToAP(char * ssid, char*  password)** tells the ESP8266 to connect to an accesspoint\n* **ssid** the ssid (station name) to be used. Note that this method uses char arrays as input. See http://arduino.cc/en/Reference/StringToCharArray for how to convert an arduino string object to a char array (max 15 chars)\n* **password** the access point password wpa/wpa2 is assumed (max 15 chars)\n* **return** will return a true if a valid IP was received within the time limit (15 seconds)\n* **Example:** `boolean apConnected = wifi.connectToAP(\"myaccesspoint\", \"password123\");`\n\n**boolean isConnectedToAP()** checks if the module is connected with a valid IP\n* **return** will return a true if the module has an valid IP address\n* **Example:** `boolean apConnected = wifi.isConnectedToAP();`\n\n## Connecting to a server\n**boolean connectToServer(char* ip, char* port)** tells the ESP8266 to open a connection to a server\n* **ip** the IP-address of the server to connect to\n* **port** the port number to be used\n* **return** true if connection is established within 5 seconds\n* **Example:** `boolean serverConnected =  wifi.connectToServer(\"192.168.5.123\", \"2121\");`\n\n**boolean isConnectedToServer()** checks if a server is connected\n* **return** will return a true if we are connected to a server\n* **Example:** `boolean serverConnected = wifi.isConnectedToServer();`\n\n**setTransportToTCP() AND setTransportToUDP()** tells the ESP8266 which transport to use when connecting to a server. Default is TCP.\n\n## Disconnecting from a server\n**disconnectFromServer()** tells the ESP8266 to close the server connection\n* **Example:** `wifi.disconnectFromServer();`\n\n## Sending a message\n**boolean send(char channel, char * message)** sends a message - alias for send(char channel, char * message, true)\n* **channel** Set to **SERVER** if you want to send to server. If we are the server, the value can be between '1'-'3'\n* **message** a character array, max 25 characters long.\n* **return** true if the message was sent\n* **Example:** `boolean sendOk = wifi.send(SERVER, \"Hello World!\");`\n\n**boolean send(char channel, char * message, boolean sendNow)** sends or queues a message for later sending\n* **channel** Set to **SERVER** if you want to send to server. If we are the server, the value can be between '1'-'3'\n* **message** a character array, max 25 characters long.\n* **sendNow** if false, the message is appended to a buffer, if true the message is sent right away\n* **return** true if the message was sent\n* **Example:** \n```\nwifi.send(SERVER, \"You\", false);\nwifi.send(SERVER, \" are \", false);\nwifi.send(SERVER, \"fantastic!\", true); // ie wifi.send(SERVER, \"fantastic!\");\n```\n**endSendWithNewline(bool endSendWithNewline)** by default all messages are sent with newline and carrage return (println), you can disable this\n* **endSendWithNewline** sent messages with print instead of println\n* **Example:** `wifi.endSendWithNewline(false);`\n\n## Checking Client Connections\n**boolean checkConnections(&connections)** - Updates pre-initialised pointer to\nWifiConnection \\*connections.\n* **return** true if client is connected\n* Updated pointer is array of 3 connections:\n  * **boolean connected** true if connected.\n  * **char channel** channel number, can be passed to `send`.\n* **Example:**\n```\nWifiConnection *connections;\n\nwifi.checkConnections(&connections);\nfor (int i = 0; i < MAX_CONNECTIONS; i++) {\n  if (connections[i].connected) {\n    // See if there is a message\n    WifiMessage msg = wifi.getIncomingMessage();\n    // Check message is there\n    if (msg.hasData) {\n      processCommand(msg);\n    }\n  }\n}\n```\n\n## Check Connection\n**boolean isConnection(void)** - Returns true if client is connected,\notherwise false. Use as above without WifiConnection pointer if not\nbothered about multi-client.\n\n## Get Incoming Message From Connected Client\n**WifiMessage getIncomingMessage(void)** - checks serial buffer for messages.\nReturn is WifiMessage type as below. See example Check Client Connection\nexample for usage.\n\n## Receiving messages\n**WifiMessage listenForIncomingMessage(int timeoutMillis)** will listen for new messages up to timeoutMillis milliseconds. Call this method as often as possible and with as large timeoutMillis as possible to be able to catch as many messages as possible..\n* **timeoutMillis** the maximum number of milliseconds to look for a new incoming message\n* **return** WifiMessage contains:\n * **boolean hasData** true if a message was received\n * **char channel** tells you if the message was received from the server (channel == SERVER) or another source\n * **char * message** the message as a character array (up to the first 25 characters)\n* **Example:** \n```\nvoid loop(){\n    WifiMessage in = wifi.listenForIncomingMessage(6000);\n    if (in.hasData) {\n        Serial.print(\"Incoming message:\");\n        Serial.println(in.message);\n        if(in.channel == SERVER)\n            Serial.println(\"From server\");\n        else{\n            Serial.print(\"From channel:\");\n            Serial.println(in.channel);\n        }\n    }\n    // Do other stuff\n }\n```\n\n## Local access point and local server\n**boolean startLocalAPAndServer(char* ssid, char* password, char* channel, char* port)** will create an local access point and start a local server\n* **ssid** the name for your access point, max 15 characters\n* **password** the password for your access point, max 15 characters\n* **channel** the channel for your access point\n* **port** the port for your local server, TCP only\n* **return** true if the local access point and server was configured and started\n* **Example:** `boolean localAPAndServerStarted = wifi.startLocalAPAndServer(\"my_ap\", \"secret_pwd\", \"5\", \"2121\");`\n\n**boolean stopLocalAPAndServer()** disable the accesspoint (the server will not be stopped, since a restart is needed)\n* **return** true if the local access point was stopped\n* **Example:** `boolean localAPAndServerStopped = wifi.stopLocalAPAndServer();`\n\n**boolean isLocalAPAndServerRunning()** check if local access point and server is running\n* **return** true if the local access point and local server is running\n* **Example:** `boolean localAPAndServerRunning = wifi.isLocalAPAndServerRunning();`\n\n## Re-connect functionality\nEverytime send(...)  and listenForIncomingMessage(..) is called a watchdog checks that the configured access point, server and local access point and server is still running, if not they will be restarted or re-connected. The same thing happens if the ESP8266 should reset.\nNote: It is really only the send method that can detect a lost connection to the server. To be sure you are connected, do a send once in a while..\n\n## Avanced configuration\nIn SerialESP8266wifi.h you can change some stuff:\n* **HW_RESET_RETRIES 3** - is the maximum number of times begin() will try to start the ESP8266 module\n* **SERVER_CONNECT_RETRIES_BEFORE_HW_RESET 30** - is the nr of time the watchdog will try to establish connection to a server before a hardware reset of the ESP8266 is performed\n* The maximum number of characters for incoming and outgoing messages can be changes by editing:\n    * char msgOut[26];\n    * char msgIn[26];\n* If the limit for ssid and password length does not suite you, please change:\n    * char _ssid[16];\n    * char _password[16];\n    *  char _localAPSSID[16];\n    *  char _localAPPassword[16];\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
  },
  {
    "path": "SerialESP8266wifi.cpp",
    "content": "//\n//  Serialesp8266wifi.cpp\n//\n//\n//  Created by Jonas Ekstrand on 2015-02-20.\n//\n//\n\n#include \"SerialESP8266wifi.h\"\n#include \"Arduino.h\"\n\n// Workaround for http://gcc.gnu.org/bugzilla/show_bug.cgi?id=34734\n#ifdef PROGMEM\n#undef PROGMEM\n#define PROGMEM __attribute__((section(\".progmem.data\")))\n#endif\n\nconst char OK[] PROGMEM = \"OK\";\nconst char FAIL[] PROGMEM = \"FAIL\";\nconst char ERROR[] PROGMEM = \"ERROR\";\nconst char NO_CHANGE[] PROGMEM = \"no change\";\n\nconst char SEND_OK[] PROGMEM = \"SEND OK\";\nconst char LINK_IS_NOT[] PROGMEM = \"link is not\";\nconst char PROMPT[] PROGMEM = \">\";\nconst char BUSY[] PROGMEM =  \"busy\";\nconst char LINKED[] PROGMEM = \"Linked\";\nconst char ALREADY[] PROGMEM = \"ALREAY\";//yes typo in firmware..\nconst char READY[] PROGMEM = \"ready\";\nconst char NO_IP[] PROGMEM = \"0.0.0.0\";\n\nconst char CIPSEND[] PROGMEM = \"AT+CIPSEND=\";\nconst char CIPSERVERSTART[] PROGMEM = \"AT+CIPSERVER=1,\";\nconst char CIPSERVERSTOP[] PROGMEM = \"AT+CIPSERVER=0\";\nconst char CIPSTART[] PROGMEM = \"AT+CIPSTART=4,\\\"\";\nconst char CIPCLOSE[] PROGMEM = \"AT+CIPCLOSE=4\";\nconst char TCP[] PROGMEM = \"TCP\";\nconst char UDP[] PROGMEM = \"UDP\";\n\nconst char CWJAP[] PROGMEM = \"AT+CWJAP=\\\"\";\n\nconst char CWMODE_1[] PROGMEM = \"AT+CWMODE=1\";\nconst char CWMODE_3[] PROGMEM = \"AT+CWMODE=3\";\nconst char CWMODE_CHECK[] PROGMEM = \"AT+CWMODE?\";\nconst char CWMODE_OK[] PROGMEM = \"+CWMODE:1\";\n\nconst char CIFSR[] PROGMEM = \"AT+CIFSR\";\nconst char CIPMUX_1[] PROGMEM = \"AT+CIPMUX=1\";\n\nconst char ATE0[] PROGMEM = \"ATE0\";\nconst char ATE1[] PROGMEM = \"ATE1\";\n\nconst char CWSAP[] PROGMEM = \"AT+CWSAP=\\\"\";\n\nconst char IPD[] PROGMEM = \"IPD,\";\nconst char CONNECT[] PROGMEM = \"CONNECT\";\nconst char CLOSED[] PROGMEM = \"CLOSED\";\n\nconst char COMMA[] PROGMEM = \",\";\nconst char COMMA_1[] PROGMEM = \"\\\",\";\nconst char COMMA_2[] PROGMEM = \"\\\",\\\"\";\nconst char THREE_COMMA[] PROGMEM = \",3\";\nconst char DOUBLE_QUOTE[] PROGMEM = \"\\\"\";\nconst char EOL[] PROGMEM = \"\\n\";\n\nconst char STAIP[] PROGMEM = \"STAIP,\\\"\";\nconst char STAMAC[] PROGMEM = \"STAMAC,\\\"\";\n\nSerialESP8266wifi::SerialESP8266wifi(Stream &serialIn, Stream &serialOut, byte resetPin) {\n    _serialIn = &serialIn;\n    _serialOut = &serialOut;\n    _resetPin = resetPin;\n\n    pinMode(_resetPin, OUTPUT);\n    digitalWrite(_resetPin, LOW);//Start with radio off\n\n    flags.connectToServerUsingTCP = true;\n    flags.endSendWithNewline = true;\n    flags.started = false;\n    flags.localServerConfigured = false;\n    flags.localApConfigured = false;\n    flags.apConfigured = false;\n    flags.serverConfigured = false;\n\n    flags.debug = false;\n    flags.echoOnOff = false;\n\n    for (int i = 0; i < MAX_CONNECTIONS; i++) {\n      _connections[i].channel = i + 0x30; // index to ASCII\n      _connections[i].connected = false;\n    }\n}\n\nSerialESP8266wifi::SerialESP8266wifi(Stream &serialIn, Stream &serialOut, byte resetPin, Stream &dbgSerial) {\n    _serialIn = &serialIn;\n    _serialOut = &serialOut;\n    _resetPin = resetPin;\n\n    pinMode(_resetPin, OUTPUT);\n    digitalWrite(_resetPin, LOW);//Start with radio off\n\n    flags.connectToServerUsingTCP = true;\n    flags.endSendWithNewline = true;\n    flags.started = false;\n    flags.localServerConfigured = false;\n    flags.localApConfigured = false;\n    flags.apConfigured = false;\n    flags.serverConfigured = false;\n\n    _dbgSerial = &dbgSerial;\n    flags.debug = true;\n    flags.echoOnOff = true;\n\n    for (int i = 0; i < MAX_CONNECTIONS; i++) {\n      _connections[i].channel = i + 0x30; // index to ASCII\n      _connections[i].connected = false;\n    }\n}\n\nvoid niceDelay(int duration){\n    unsigned long startMillis = millis();\n    while(millis() - startMillis < duration){\n        sqrt(4700);\n    }\n}\n\nvoid SerialESP8266wifi::endSendWithNewline(bool endSendWithNewline){\n    flags.endSendWithNewline = endSendWithNewline;\n}\n\nbool SerialESP8266wifi::begin() {\n    msgOut[0] = '\\0';\n    msgIn[0] = '\\0';\n    flags.connectedToServer = false;\n    flags.localServerConfigured = false;\n    flags.localApConfigured = false;\n    serverRetries = 0;\n\n    //Do a HW reset\n    bool statusOk = false;\n    byte i;\n    for(i =0; i<HW_RESET_RETRIES; i++){\n        readCommand(10, NO_IP); //Cleanup\n        digitalWrite(_resetPin, LOW);\n        niceDelay(500);\n        digitalWrite(_resetPin, HIGH); // select the radio\n        // Look for ready string from wifi module\n        statusOk = readCommand(3000, READY) == 1;\n        if(statusOk)\n            break;\n    }\n    if (!statusOk)\n        return false;\n\n    //Turn local AP = off\n    writeCommand(CWMODE_1, EOL);\n    if (readCommand(1000, OK, NO_CHANGE) == 0)\n        return false;\n\n    // Set echo on/off\n    if(flags.echoOnOff)//if echo = true\n        writeCommand(ATE1, EOL);\n    else\n        writeCommand(ATE0, EOL);\n    if (readCommand(1000, OK, NO_CHANGE) == 0)\n        return false;\n\n    // Set mux to enable multiple connections\n    writeCommand(CIPMUX_1, EOL);\n    flags.started = readCommand(3000, OK, NO_CHANGE) > 0;\n    return flags.started;\n}\n\nbool SerialESP8266wifi::isStarted(){\n    return flags.started;\n}\n\nbool SerialESP8266wifi::restart() {\n    return begin()\n        && (!flags.localApConfigured || startLocalAp())\n        && (!flags.localServerConfigured || startLocalServer())\n        && (!flags.apConfigured || connectToAP())\n        && (!flags.serverConfigured || connectToServer());\n}\n\nbool SerialESP8266wifi::connectToAP(String& ssid, String& password) {\n    return connectToAP(ssid.c_str(), password.c_str());\n}\n\nbool SerialESP8266wifi::connectToAP(const char* ssid, const char* password){//TODO make timeout config or parameter??\n    strncpy(_ssid, ssid, sizeof _ssid);\n    strncpy(_password, password, sizeof _password);\n    flags.apConfigured = true;\n    return connectToAP();\n}\n\nbool SerialESP8266wifi::connectToAP(){\n    writeCommand(CWJAP);\n    _serialOut -> print(_ssid);\n    writeCommand(COMMA_2);\n    _serialOut -> print(_password);\n    writeCommand(DOUBLE_QUOTE, EOL);\n\n    readCommand(15000, OK, FAIL);\n    return isConnectedToAP();\n}\n\nbool SerialESP8266wifi::isConnectedToAP(){\n    writeCommand(CIFSR, EOL);\n    byte code = readCommand(350, NO_IP, ERROR);\n    readCommand(10, OK); //cleanup\n    return (code == 0);\n}\n\nchar* SerialESP8266wifi::getIP(){\n    msgIn[0] = '\\0';\n    writeCommand(CIFSR, EOL);\n    byte code = readCommand(1000, STAIP, ERROR);\n    if (code == 1) {\n        // found staip\n        readBuffer(&msgIn[0], sizeof(msgIn) - 1, '\"');\n        readCommand(10, OK, ERROR);\n        return &msgIn[0];\n    }\n    readCommand(1000, OK, ERROR);\n    return &msgIn[0];\n}\n\nchar* SerialESP8266wifi::getMAC(){\n    msgIn[0] = '\\0';\n    writeCommand(CIFSR, EOL);\n    byte code = readCommand(1000, STAMAC, ERROR);\n    if (code == 1) {\n        // found stamac\n        readBuffer(&msgIn[0], sizeof(msgIn) - 1, '\"');\n        readCommand(10, OK, ERROR);\n        return &msgIn[0];\n    }\n    readCommand(1000, OK, ERROR);\n    return &msgIn[0];\n}\n\nvoid SerialESP8266wifi::setTransportToUDP(){\n    flags.connectToServerUsingTCP = false;\n}\n\nvoid SerialESP8266wifi::setTransportToTCP(){\n    flags.connectToServerUsingTCP = true;\n}\n\nbool SerialESP8266wifi::connectToServer(String& ip, String& port) {\n    return connectToServer(ip.c_str(), port.c_str());\n}\n\nbool SerialESP8266wifi::connectToServer(const char* ip, const char* port){//TODO make timeout config or parameter??\n    strncpy(_ip, ip, sizeof _ip);\n    strncpy(_port, port, sizeof _port);\n    flags.serverConfigured = true;\n    return connectToServer();\n}\n\n\nbool SerialESP8266wifi::connectToServer(){\n    writeCommand(CIPSTART);\n    if (flags.connectToServerUsingTCP)\n        writeCommand(TCP);\n    else\n        writeCommand(UDP);\n    writeCommand(COMMA_2);\n    _serialOut -> print(_ip);\n    writeCommand(COMMA_1);\n    _serialOut -> println(_port);\n\n    flags.connectedToServer = (readCommand(10000, LINKED, ALREADY) > 0);\n\n    if(flags.connectedToServer)\n        serverRetries = 0;\n    return flags.connectedToServer;\n}\n\n\nvoid SerialESP8266wifi::disconnectFromServer(){\n    flags.connectedToServer = false;\n    flags.serverConfigured = false;//disable reconnect\n    writeCommand(CIPCLOSE);\n    readCommand(2000, OK); //fire and forget in this case..\n}\n\n\nbool SerialESP8266wifi::isConnectedToServer(){\n    if(flags.connectedToServer)\n        serverRetries = 0;\n    return flags.connectedToServer;\n}\n\nbool SerialESP8266wifi::startLocalAPAndServer(const char* ssid, const char* password, const char* channel, const char* port){\n    strncpy(_localAPSSID, ssid, sizeof _localAPSSID);\n    strncpy(_localAPPassword, password, sizeof _localAPPassword);\n    strncpy(_localAPChannel, channel, sizeof _localAPChannel);\n    strncpy(_localServerPort, port, sizeof _localServerPort);\n\n    flags.localApConfigured = true;\n    flags.localServerConfigured = true;\n    return startLocalAp() && startLocalServer();\n}\n\nbool SerialESP8266wifi::startLocalAP(const char* ssid, const char* password, const char* channel){\n    strncpy(_localAPSSID, ssid, sizeof _localAPSSID);\n    strncpy(_localAPPassword, password, sizeof _localAPPassword);\n    strncpy(_localAPChannel, channel, sizeof _localAPChannel);\n\n    flags.localApConfigured = true;\n    return startLocalAp();\n}\n\nbool SerialESP8266wifi::startLocalServer(const char* port) {\n    strncpy(_localServerPort, port, sizeof _localServerPort);\n    flags.localServerConfigured = true;\n    return startLocalServer();\n}\n\nbool SerialESP8266wifi::startLocalServer(){\n    // Start local server\n    writeCommand(CIPSERVERSTART);\n    _serialOut -> println(_localServerPort);\n\n    flags.localServerRunning = (readCommand(2000, OK, NO_CHANGE) > 0);\n    return flags.localServerRunning;\n}\n\nbool SerialESP8266wifi::startLocalAp(){\n    // Start local ap mode (eg both local ap and ap)\n    writeCommand(CWMODE_3, EOL);\n    if (!readCommand(2000, OK, NO_CHANGE))\n        return false;\n\n    // Configure the soft ap\n    writeCommand(CWSAP);\n    _serialOut -> print(_localAPSSID);\n    writeCommand(COMMA_2);\n    _serialOut -> print(_localAPPassword);\n    writeCommand(COMMA_1);\n    _serialOut -> print(_localAPChannel);\n    writeCommand(THREE_COMMA, EOL);\n\n    flags.localApRunning = (readCommand(5000, OK, ERROR) == 1);\n    return flags.localApRunning;\n}\n\nbool SerialESP8266wifi::stopLocalServer(){\n    writeCommand(CIPSERVERSTOP, EOL);\n    boolean stopped = (readCommand(2000, OK, NO_CHANGE) > 0);\n    flags.localServerRunning = !stopped;\n    flags.localServerConfigured = false; //to prevent autostart\n    return stopped;\n}\n\nbool SerialESP8266wifi::stopLocalAP(){\n    writeCommand(CWMODE_1, EOL);\n\n    boolean stopped = (readCommand(2000, OK, NO_CHANGE) > 0);\n    flags.localApRunning = !stopped;\n    flags.localApConfigured = false; //to prevent autostart\n    return stopped;\n}\n\nbool SerialESP8266wifi::stopLocalAPAndServer(){\n    return stopLocalAP() && stopLocalServer();\n}\n\nbool SerialESP8266wifi::isLocalAPAndServerRunning(){\n    return flags.localApRunning & flags.localServerRunning;\n}\n\n// Performs a connect retry (or hardware reset) if not connected\nbool SerialESP8266wifi::watchdog() {\n    if (serverRetries >= SERVER_CONNECT_RETRIES_BEFORE_HW_RESET) {\n        // give up, do a hardware reset\n        return restart();\n    }\n    if (flags.serverConfigured && !flags.connectedToServer) {\n        serverRetries++;\n        if (flags.apConfigured && !isConnectedToAP()) {\n            if (!connectToAP()) {\n                // wait a bit longer, then check again\n                niceDelay(2000);\n                if (!isConnectedToAP()) {\n                    return restart();\n                }\n            }\n        }\n        return connectToServer();\n    }\n    return true;\n}\n\n/*\n * Send string (if channel is connected of course)\n */\nbool SerialESP8266wifi::send(char channel, String& message, bool sendNow) {\n    return send(channel, message.c_str(), sendNow);\n}\n\nbool SerialESP8266wifi::send(char channel, const char * message, bool sendNow){\n    watchdog();\n    byte avail = sizeof(msgOut) - strlen(msgOut) - 1;\n    strncat(msgOut, message, avail);\n    if (!sendNow)\n        return true;\n    byte length = strlen(msgOut);\n\n    if(flags.endSendWithNewline)\n        length += 2;\n\n    writeCommand(CIPSEND);\n    _serialOut -> print(channel);\n    writeCommand(COMMA);\n    _serialOut -> println(length);\n    byte prompt = readCommand(1000, PROMPT, LINK_IS_NOT);\n    if (prompt != 2) {\n        if(flags.endSendWithNewline)\n            _serialOut -> println(msgOut);\n        else\n            _serialOut -> print(msgOut);\n        byte sendStatus = readCommand(5000, SEND_OK, BUSY);\n        if (sendStatus == 1) {\n            msgOut[0] = '\\0';\n            if(channel == SERVER)\n                flags.connectedToServer = true;\n            return true;\n        }\n    }\n    //else\n    if(channel == SERVER)\n        flags.connectedToServer = false;\n    else\n        _connections[channel-0x30].connected = false;\n    msgOut[0] = '\\0';\n    return false;\n}\n\n// Checks to see if there is a client connection\nbool SerialESP8266wifi::isConnection(void) {\n    WifiConnection *connections;\n\n    // return the first channel, assume single connection use\n    return checkConnections(&connections);\n}\n\n// Updates private connections struct and make passed pointer point to data\nbool SerialESP8266wifi::checkConnections(WifiConnection **pConnections) {\n    watchdog();\n    // setup buffers on stack & copy data from PROGMEM pointers\n    char buf1[16] = {'\\0'};\n    char buf2[16] = {'\\0'};\n    char buf3[16] = {'\\0'};\n    strcpy_P(buf1, CONNECT);\n    strcpy_P(buf2, READY);\n    strcpy_P(buf3, CLOSED);\n    byte len1 = strlen(buf1);\n    byte len2 = strlen(buf2);\n    byte len3 = strlen(buf3);\n    byte pos = 0;\n    byte pos1 = 0;\n    byte pos2 = 0;\n    byte pos3 = 0;\n    byte ret = 0;\n    char ch = '-';\n\n    // unload buffer and check match\n    while (_serialIn->available()) {\n        char c = readChar();\n        // skip white space\n        if (c != ' ') {\n          // get out of here if theres a message\n          if (c == '+')\n            break;\n          // first char is channel\n          if (pos == 0)\n            ch = c;\n          pos++;\n          pos1 = (c == buf1[pos1]) ? pos1 + 1 : 0;\n          pos2 = (c == buf2[pos2]) ? pos2 + 1 : 0;\n          pos3 = (c == buf3[pos3]) ? pos3 + 1 : 0;\n          if (len1 > 0 && pos1 == len1) {\n              ret = 1;\n              break;\n          }\n          if (len2 > 0 && pos2 == len2) {\n              ret = 2;\n              break;\n          }\n          if (len3 > 0 && pos3 == len3) {\n              ret = 3;\n              break;\n          }\n        }\n    }\n\n    if (ret == 2)\n      restart();\n\n    // new connection\n    if (ret == 1) {\n      _connections[ch-0x30].connected = true;\n      *pConnections = _connections;\n      if (ch == SERVER)\n          flags.connectedToServer = true;\n      return 1;\n    }\n\n    // channel disconnected\n    if (ret == 3) {\n      _connections[ch-0x30].connected = false;\n      *pConnections = _connections;\n      if (ch == SERVER)\n          flags.connectedToServer = false;\n      return 0;\n    }\n\n    // nothing has changed return single connection status\n    *pConnections = _connections;\n    return _connections[0].connected;\n}\n\nWifiMessage SerialESP8266wifi::listenForIncomingMessage(int timeout){\n    watchdog();\n    char buf[16] = {'\\0'};\n    msgIn[0] = '\\0';\n\n    static WifiMessage msg;\n\n    msg.hasData = false;\n    msg.channel = '-';\n    msg.message = msgIn;\n\n    //TODO listen for unlink etc...\n    byte msgOrRestart = readCommand(timeout, IPD, READY);\n\n    //Detected a esp8266 restart\n    if (msgOrRestart == 2){\n        restart();\n        return msg;\n    }\n    //Message received..\n    else if (msgOrRestart == 1) {\n        char channel = readChar();\n        if (channel == SERVER)\n            flags.connectedToServer = true;\n        readChar(); // removing comma\n        readBuffer(&buf[0], sizeof(buf) - 1, ':'); // read char count\n        readChar(); // removing ':' delim\n        byte length = atoi(buf);\n        readBuffer(&msgIn[0], min(length, sizeof(msgIn) - 1));\n        msg.hasData = true;\n        msg.channel = channel;\n        msg.message = msgIn;\n        readCommand(10, OK); // cleanup after rx\n    }\n    return msg;\n}\n\nWifiMessage SerialESP8266wifi::getIncomingMessage(void) {\n    watchdog();\n    char buf[16] = {'\\0'};\n    msgIn[0] = '\\0';\n\n    static WifiMessage msg;\n\n    msg.hasData = false;\n    msg.channel = '-';\n    msg.message = msgIn;\n\n    // See if a message has come in (block 1s otherwise misses?)\n    byte msgOrRestart = readCommand(10, IPD, READY);\n\n    //Detected a esp8266 restart\n    if (msgOrRestart == 2){\n        restart();\n        return msg;\n    }\n    //Message received..\n    else if (msgOrRestart == 1) {\n        char channel = readChar();\n        if (channel == SERVER)\n            flags.connectedToServer = true;\n        readChar(); // removing comma\n        readBuffer(&buf[0], sizeof(buf) - 1, ':'); // read char count\n        readChar(); // removing ':' delim\n        byte length = atoi(buf);\n        readBuffer(&msgIn[0], min(length, sizeof(msgIn) - 1));\n        msg.hasData = true;\n        msg.channel = channel;\n        msg.message = msgIn;\n        readCommand(10, OK); // cleanup after rx\n    }\n    return msg;\n}\n\n// Writes commands (from PROGMEM) to serial output\nvoid SerialESP8266wifi::writeCommand(const char* text1 = NULL, const char* text2) {\n    char buf[16] = {'\\0'};\n    strcpy_P(buf, (char *) text1);\n    _serialOut->print(buf);\n    if (text2 == EOL) {\n        _serialOut->println();\n    } else if (text2 != NULL) {\n        strcpy_P(buf, (char *) text2);\n        _serialOut->print(buf);\n    }\n}\n\n// Reads from serial input until a expected string is found (or until timeout)\n// NOTE: strings are stored in PROGMEM (auto-copied by this method)\nbyte SerialESP8266wifi::readCommand(int timeout, const char* text1, const char* text2) {\n    // setup buffers on stack & copy data from PROGMEM pointers\n    char buf1[16] = {'\\0'};\n    char buf2[16] = {'\\0'};\n    if (text1 != NULL)\n        strcpy_P(buf1, (char *) text1);\n    if (text2 != NULL)\n        strcpy_P(buf2, (char *) text2);\n    byte len1 = strlen(buf1);\n    byte len2 = strlen(buf2);\n    byte pos1 = 0;\n    byte pos2 = 0;\n\n    // read chars until first match or timeout\n    unsigned long stop = millis() + timeout;\n    do {\n        while (_serialIn->available()) {\n            char c = readChar();\n            pos1 = (c == buf1[pos1]) ? pos1 + 1 : 0;\n            pos2 = (c == buf2[pos2]) ? pos2 + 1 : 0;\n            if (len1 > 0 && pos1 == len1)\n                return 1;\n            if (len2 > 0 && pos2 == len2)\n                return 2;\n        }\n        niceDelay(10);\n    } while (millis() < stop);\n    return 0;\n}\n\n// Unload buffer without delay\n/*byte ESP8266wifiESP8266wifi::readCommand(const char* text1, const char* text2) {\n    // setup buffers on stack & copy data from PROGMEM pointers\n    char buf1[16] = {'\\0'};\n    char buf2[16] = {'\\0'};\n    if (text1 != NULL)\n        strcpy_P(buf1, (char *) text1);\n    if (text2 != NULL)\n        strcpy_P(buf2, (char *) text2);\n    byte len1 = strlen(buf1);\n    byte len2 = strlen(buf2);\n    byte pos1 = 0;\n    byte pos2 = 0;\n\n    // read chars until first match or timeout\n    while (_serialIn->available()) {\n        char c = readChar();\n        pos1 = (c == buf1[pos1]) ? pos1 + 1 : 0;\n        pos2 = (c == buf2[pos2]) ? pos2 + 1 : 0;\n        if (len1 > 0 && pos1 == len1)\n            return 1;\n        if (len2 > 0 && pos2 == len2)\n            return 2;\n    }\n    return 0;\n}*/\n\n// Reads count chars to a buffer, or until delim char is found\nbyte SerialESP8266wifi::readBuffer(char* buf, byte count, char delim) {\n    byte pos = 0;\n    char c;\n    while (_serialIn->available() && pos < count) {\n        c = readChar();\n        if (c == delim)\n            break;\n        buf[pos++] = c;\n    }\n    buf[pos] = '\\0';\n    return pos;\n}\n\n// Reads a single char from serial input (with debug printout if configured)\nchar SerialESP8266wifi::readChar() {\n    char c = _serialIn->read();\n    if (flags.debug)\n        _dbgSerial->print(c);\n    else\n        sqrt(12345);//delayMicroseconds(50); // don't know why\n    return c;\n}\n"
  },
  {
    "path": "SerialESP8266wifi.h",
    "content": "//\n//  SerialESP8266wifi.h\n//\n//\n//  Created by Jonas Ekstrand on 2015-02-20.\n//  ESP8266 AT cmd ref from https://github.com/espressif/esp8266_at/wiki/CIPSERVER\n//\n//\n\n#ifndef SerialESP8266wifi_h\n#define SerialESP8266wifi_h\n\n#define HW_RESET_RETRIES 3\n#define SERVER_CONNECT_RETRIES_BEFORE_HW_RESET 3\n\n#if defined(ARDUINO) && ARDUINO >= 100\n#include \"Arduino.h\"\n#else\n#include \"WProgram.h\"\n#endif\n\n#include <inttypes.h>\n\n#if defined(SerialESP8266)\n#include <pgmspace.h>\n#else\n#include <avr/pgmspace.h>\n#endif\n\n#include \"HardwareSerial.h\"\n\n#define SERVER '4'\n#define MAX_CONNECTIONS 3\n\n#define MSG_BUFFER_MAX 128\n\nstruct WifiMessage{\npublic:\n    bool hasData:1;\n    char channel;\n    char * message;\n};\n\nstruct WifiConnection{\npublic:\n    char channel;\n    bool connected:1;\n};\n\nstruct Flags   // 1 byte value (on a system where 8 bits is a byte\n{\n    bool started:1, \n         echoOnOff:1, \n         debug:1, \n         serverConfigured:1,            // true if a connection to a remote server is configured\n         connectedToServer:1,           // true if a connection to a remote server is established\n         apConfigured:1,                // true if the module is configured as a client station\n         localApConfigured:1,\n         localServerConfigured:1,\n         localApRunning:1, \n         localServerRunning:1, \n         endSendWithNewline:1, \n         connectToServerUsingTCP:1;\n};\n\nclass SerialESP8266wifi\n{\n    \npublic:\n    /*\n     * Will pull resetPin low then high to reset esp8266, connect this pin to CHPD pin\n     */\n    SerialESP8266wifi(Stream &serialIn, Stream &serialOut, byte resetPin);\n    \n    \n    /*\n     * Will pull resetPin low then high to reset esp8266, connect this pin to CHPD pin\n     */\n    SerialESP8266wifi(Stream &serialIn, Stream &serialOut, byte resetPin, Stream &dbgSerial);\n    \n    /*\n     * Will do hw reset and set inital configuration, will try this HW_RESET_RETRIES times.\n     */\n    bool begin(); // reset and set echo and other stuff\n    \n    bool isStarted();\n    \n    /*\n     * Connect to AP using wpa encryption\n     * (reconnect logic is applied, if conn lost or not established, or esp8266 restarted)\n     */\n    bool connectToAP(String& ssid, String& password);\n    bool connectToAP(const char* ssid, const char* password);\n    bool isConnectedToAP();\n    char* getIP();\n    char* getMAC();\n    \n    /*\n     * Evaluate the connection and perform reconnects if needed. Eventually perform reset and restart.\n     *\n     */\n    bool watchdog();\n    \n    /*\n     * Connecting with TCP to server\n     * (reconnect logic is applied, if conn lost or not established, or esp8266 restarted)\n     */\n    \n    void setTransportToUDP();\n    //Default..\n    void setTransportToTCP();\n    bool connectToServer(String& ip, String& port);\n    bool connectToServer(const char* ip, const char* port);\n    void disconnectFromServer();\n    bool isConnectedToServer();\n    \n    /*\n     * Starting local AP and local TCP-server\n     * (reconnect logic is applied, if conn lost or not established, or esp8266 restarted)\n     */\n    bool startLocalAPAndServer(const char* ssid, const char* password, const char* channel,const char* port);\n    bool startLocalAP(const char* ssid, const char* password, const char* channel);\n    bool startLocalServer(const char* port);\n    bool stopLocalAPAndServer();\n    bool stopLocalAP();\n    bool stopLocalServer();\n    bool isLocalAPAndServerRunning();\n    \n    \n    /*\n     * Send string (if channel is connected of course)\n     */\n    bool send(char channel, String& message, bool sendNow = true);\n    bool send(char channel, const char * message, bool sendNow = true);\n    \n    /*\n     * Default is true.\n     */\n    void endSendWithNewline(bool endSendWithNewline);\n    \n    /*\n     * Scan for incoming message, do this as often and as long as you can (use as sleep in loop)\n     */\n    WifiMessage listenForIncomingMessage(int timeoutMillis);\n    WifiMessage getIncomingMessage(void);\n    bool isConnection(void);\n    bool checkConnections(WifiConnection **pConnections);\n    \nprivate:\n    Stream* _serialIn;\n    Stream* _serialOut;\n    byte _resetPin;\n    \n    Flags flags;\n    \n    bool connectToServer();\n    char _ip[16];\n    char _port[6];\n    \n    bool connectToAP();\n    char _ssid[16];\n    char _password[16];\n    \n    bool startLocalAp();\n    bool startLocalServer();\n    char _localAPSSID[16];\n    char _localAPPassword[16];\n    char _localAPChannel[3];\n    char _localServerPort[6];\n    WifiConnection _connections[MAX_CONNECTIONS];\n    \n    bool restart();\n    \n    byte serverRetries;\n    \n    \n    char msgOut[MSG_BUFFER_MAX];//buffer for send method\n    char msgIn[MSG_BUFFER_MAX]; //buffer for listen method = limit of incoming message..\n\n    void writeCommand(const char* text1, const char* text2 = NULL);\n    byte readCommand(int timeout, const char* text1 = NULL, const char* text2 = NULL);\n    //byte readCommand(const char* text1, const char* text2);\n    byte readBuffer(char* buf, byte count, char delim = '\\0');\n    char readChar();\n    Stream* _dbgSerial;\n};\n\n#endif\n"
  },
  {
    "path": "examples/SerialESP8266_library_test/SerialESP8266_library_test.ino",
    "content": "#include <SoftwareSerial.h>\n#include <SerialESP8266wifi.h>\n\n#define sw_serial_rx_pin 4 //  Connect this pin to TX on the esp8266\n#define sw_serial_tx_pin 6 //  Connect this pin to RX on the esp8266\n#define esp8266_reset_pin 5 // Connect this pin to CH_PD on the esp8266, not reset. (let reset be unconnected)\n\nSoftwareSerial swSerial(sw_serial_rx_pin, sw_serial_tx_pin);\n\n// the last parameter sets the local echo option for the ESP8266 module..\nSerialESP8266wifi wifi(swSerial, swSerial, esp8266_reset_pin, Serial);//adding Serial enabled local echo and wifi debug\n\nString inputString;\nboolean stringComplete = false;\nunsigned long nextPing = 0;\n\nvoid setup() {\n  inputString.reserve(20);\n  swSerial.begin(9600);\n  Serial.begin(9600);\n  while (!Serial)\n    ;\n  Serial.println(\"Starting wifi\");\n\n  wifi.setTransportToTCP();// this is also default\n  // wifi.setTransportToUDP();//Will use UDP when connecting to server, default is TCP\n\n  wifi.endSendWithNewline(true); // Will end all transmissions with a newline and carrage return ie println.. default is true\n\n  wifi.begin();\n\n  //Turn on local ap and server (TCP)\n  wifi.startLocalAPAndServer(\"MY_CONFIG_AP\", \"password\", \"5\", \"2121\");\n\n  wifi.connectToAP(\"wifissid\", \"wifipass\");\n  wifi.connectToServer(\"192.168.0.28\", \"2121\");\n  wifi.send(SERVER, \"ESP8266 test app started\");\n}\n\nvoid loop() {\n\n  //Make sure the esp8266 is started..\n  if (!wifi.isStarted())\n    wifi.begin();\n\n  //Send what you typed in the arduino console to the server\n  static char buf[20];\n  if (stringComplete) {\n    inputString.toCharArray(buf, sizeof buf);\n    wifi.send(SERVER, buf);\n    inputString = \"\";\n    stringComplete = false;\n  }\n\n  //Send a ping once in a while..\n  if (millis() > nextPing) {\n    wifi.send(SERVER, \"Ping ping..\");\n    nextPing = millis() + 10000;\n  }\n\n  //Listen for incoming messages and echo back, will wait until a message is received, or max 6000ms..\n  WifiMessage in = wifi.listenForIncomingMessage(6000);\n  if (in.hasData) {\n    if (in.channel == SERVER)\n      Serial.println(\"Message from the server:\");\n    else\n      Serial.println(\"Message a local client:\");\n    Serial.println(in.message);\n    //Echo back;\n    wifi.send(in.channel, \"Echo:\", false);\n    wifi.send(in.channel, in.message);\n    nextPing = millis() + 10000;\n  }\n\n  //If you want do disconnect from the server use:\n  // wifi.disconnectFromServer();\n\n}\n\n//Listen for serial input from the console\nvoid serialEvent() {\n  while (Serial.available()) {\n    char inChar = (char)Serial.read();\n    inputString += inChar;\n    if (inChar == '\\n') {\n      stringComplete = true;\n    }\n  }\n}\n"
  },
  {
    "path": "examples/SerialESP8266_tcp_cli/SerialESP8266_tcp_cli.ino",
    "content": "#include <SoftwareSerial.h>\n#include <SerialESP8266wifi.h>\n\n/* TCP server/client example, that manages client connections, checks for messages\n *  when client is connected and parses commands. Connect to the ESP8266 IP using\n * a TCP client such as telnet, eg: telnet 192.168.0.X 2121\n *  \n *  ESP8266 should be AT firmware based on 1.5 SDK or later\n *\n * 2016 - J.Whittington - engineer.john-whittington.co.uk\n */\n\n#define sw_serial_rx_pin 4 //  Connect this pin to TX on the esp8266\n#define sw_serial_tx_pin 6 //  Connect this pin to RX on the esp8266\n#define esp8266_reset_pin 5 // Connect this pin to CH_PD on the esp8266, not reset. (let reset be unconnected)\n\n#define SERVER_PORT \"2121\"\n#define SSID \"YourSSID\"\n#define PASSWORD \"YourPassword\"\n\nSoftwareSerial swSerial(sw_serial_rx_pin, sw_serial_tx_pin);\n\n// the last parameter sets the local echo option for the ESP8266 module..\nSerialESP8266wifi wifi(Serial, Serial, esp8266_reset_pin, swSerial);\n\nvoid processCommand(WifiMessage msg);\n\nuint8_t wifi_started = false;\n\n// TCP Commands\nconst char RST[] PROGMEM = \"RST\";\nconst char IDN[] PROGMEM = \"*IDN?\";\n\nvoid setup() {\n\n  // start debug serial\n  swSerial.begin(9600);\n  // start HW serial for ESP8266 (change baud depending on firmware)\n  Serial.begin(115200);\n  while (!Serial)\n    ;\n  Serial.println(\"Starting wifi\");\n\n  swSerial.println(\"Starting wifi\");\n  wifi.setTransportToTCP();// this is also default\n  wifi.endSendWithNewline(false); // Will end all transmissions with a newline and carrage return ie println.. default is true\n\n  wifi_started = wifi.begin();\n  if (wifi_started) {\n    wifi.connectToAP(SSID, PASSWORD);\n    wifi.startLocalServer(SERVER_PORT);\n  } else {\n    // ESP8266 isn't working..\n  }\n}\n\nvoid loop() {\n\n  static WifiConnection *connections;\n\n  // check connections if the ESP8266 is there\n  if (wifi_started)\n    wifi.checkConnections(&connections);\n\n  // check for messages if there is a connection\n  for (int i = 0; i < MAX_CONNECTIONS; i++) {\n    if (connections[i].connected) {\n      // See if there is a message\n      WifiMessage msg = wifi.getIncomingMessage();\n      // Check message is there\n      if (msg.hasData) {\n        // process the command\n        processCommand(msg);\n      }\n    }\n  }\n}\n\nvoid processCommand(WifiMessage msg) {\n  // return buffer\n  char espBuf[MSG_BUFFER_MAX];\n  // scanf holders\n  int set;\n  char str[16];\n\n  // Get command and setting\n  sscanf(msg.message,\"%15s %d\",str,&set);\n  /* swSerial.print(str);*/\n  /* swSerial.println(set);*/\n\n  if ( !strcmp_P(str,IDN) ) {\n    wifi.send(msg.channel,\"ESP8266wifi Example\");\n  }\n  // Reset system by temp enable watchdog\n  else if ( !strcmp_P(str,RST) ) {\n    wifi.send(msg.channel,\"SYSTEM RESET...\");\n    // soft reset by reseting PC\n    asm volatile (\"  jmp 0\");\n  }\n  // Unknown command\n  else {\n    wifi.send(msg.channel,\"ERR\");\n  }\n}\n"
  },
  {
    "path": "library.json",
    "content": "{\n  \"name\": \"SerialESP8266wifi\",\n  \"keywords\": \"wifi, wi-fi, http, web, server, client\",\n  \"description\": \"ESP8266 Arduino library with built in reconnect functionality\",\n  \"repository\":\n  {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/ekstrand/ESP8266wifi.git\"\n  },\n  \"frameworks\": \"arduino\",\n  \"platforms\": \"atmelavr\"\n}\n"
  }
]