├── .gitattributes ├── .gitignore ├── AppInventor ├── AppInventor_MQTT.aia ├── AppInventor_MQTT.apk ├── README.md └── mqtt_appinventor.html ├── AppInventor_CfgMQTT ├── AppInventor_MQTT_CFG.aia ├── AppInventor_MQTT_CFG.apk ├── README.md ├── cfg.txt └── mqtt_appinventor.html ├── AppInventor_CfgMQTT_TLS ├── AppInventor_MQTT_CFG_TLS.aia ├── AppInventor_MQTT_CFG_TLS.apk ├── README.md ├── cfg.txt ├── mqtt_appinventor_paho.html └── mqttws31.js ├── AppInventor_CfgMQTT_rev1 ├── AppInventor_MQTT_CFG_rev1.aia ├── AppInventor_MQTT_CFG_rev1.apk ├── README.md ├── cfg.txt ├── mqtt_appinventor_paho.html └── mqttws31.js ├── ArduinoHomeAutomation └── ArduinoHomeAutomation.ino ├── PubSubClient ├── CHANGES.txt ├── LICENSE.txt ├── README.md ├── examples │ ├── mqtt_auth │ │ └── mqtt_auth.ino │ ├── mqtt_basic │ │ └── mqtt_basic.ino │ ├── mqtt_esp8266 │ │ └── mqtt_esp8266.ino │ ├── mqtt_publish_in_callback │ │ └── mqtt_publish_in_callback.ino │ ├── mqtt_reconnect_nonblocking │ │ └── mqtt_reconnect_nonblocking.ino │ └── mqtt_stream │ │ └── mqtt_stream.ino ├── keywords.txt ├── library.properties ├── src │ ├── PubSubClient.cpp │ └── PubSubClient.h └── tests │ ├── Makefile │ ├── README.md │ ├── src │ ├── connect_spec.cpp │ ├── keepalive_spec.cpp │ ├── lib │ │ ├── Arduino.h │ │ ├── BDDTest.cpp │ │ ├── BDDTest.h │ │ ├── Buffer.cpp │ │ ├── Buffer.h │ │ ├── Client.h │ │ ├── IPAddress.cpp │ │ ├── IPAddress.h │ │ ├── ShimClient.cpp │ │ ├── ShimClient.h │ │ ├── Stream.cpp │ │ ├── Stream.h │ │ └── trace.h │ ├── publish_spec.cpp │ ├── receive_spec.cpp │ └── subscribe_spec.cpp │ ├── testcases │ ├── mqtt_basic.py │ ├── mqtt_publish_in_callback.py │ └── settings.py │ └── testsuite.py ├── README.md ├── UtilityFunctions ├── UtilityFunctions.cpp ├── UtilityFunctions.h └── library.properties ├── http_mqtt_server ├── PAGE_NetworkConfiguration.h ├── Page_Style.css.h ├── http_mqtt_server.ino └── sketch.h ├── http_mqtt_server_SSL ├── PAGE_NetworkConfiguration.h ├── Page_Style.css.h ├── http_mqtt_server_SSL.ino └── sketch.h └── webserver ├── lwipopts.h ├── mem_manager.h └── user_webserver.h /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear in the root of a volume 35 | .DocumentRevisions-V100 36 | .fseventsd 37 | .Spotlight-V100 38 | .TemporaryItems 39 | .Trashes 40 | .VolumeIcon.icns 41 | 42 | # Directories potentially created on remote AFP share 43 | .AppleDB 44 | .AppleDesktop 45 | Network Trash Folder 46 | Temporary Items 47 | .apdisk 48 | -------------------------------------------------------------------------------- /AppInventor/AppInventor_MQTT.aia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/internetofhomethings/Configurable-Web-Server/38879014a7db6cd5804a302e143d954b3d22765b/AppInventor/AppInventor_MQTT.aia -------------------------------------------------------------------------------- /AppInventor/AppInventor_MQTT.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/internetofhomethings/Configurable-Web-Server/38879014a7db6cd5804a302e143d954b3d22765b/AppInventor/AppInventor_MQTT.apk -------------------------------------------------------------------------------- /AppInventor/README.md: -------------------------------------------------------------------------------- 1 |

AppInventor Android App MQTT Example

2 | 3 | This project is an Android Application developed using App Inventor. 4 | 5 | App Inventor is accessible online at: http://ai2.appinventor.mit.edu/ 6 | 7 | This example is provided as method to interface with an MQTT broker. 8 | 9 | How it works: 10 | 11 | The App Inventor communicates with an html/JavaScript webpage using 12 | the WebViewString. WebViewString is visible to both App Inventor and JavaScript. 13 | 14 | The MQTT parameters are hard-coded into the html file mqtt_appinventor.html. 15 | 16 | var mqtturl = "ws://test.mosquitto.org:8080/mqtt";
17 | var txtopic = "MyMqttSvrRqst";
18 | var rxtopic = "MyMqttSvrRply";
19 | 20 | These values will work only with the project presented here. They will need to be 21 | modified as necessary to meet your own system requirements 22 | 23 |

Setup:

24 | 25 | 1. Connect your Android device to a PC via USB. 26 | 2. From the PC, copy the file mqtt_appinventor.html to your Android SD card at the following location:

27 | (ANDROID NAME ON PC)\Card\mqtt\mqtt_appinventor.html

28 | You can also use an Android File Manager App to make sure the file is in the proper location. 29 | I used the App ES File Explorer. With that App, the file should be placed at:

30 | /storage/extSdCard/mqtt/mqtt_appinventor.html

31 | The folder "mqtt" will need to be created. 32 | 3. Install the application "AppInventor_MQTT.apk" on the Android device. 33 | 34 | NOTE: If you want to build your own Android Application using the App Inventor web interface, 35 | import the project file AppInventor_MQTT.aia. 36 | 37 | This App assumes an ESP8266 device is running the sketch found at: 38 | 39 | https://github.com/internetofhomethings/Configurable-Web-Server 40 | 41 | For more information, check out the post at http://wp.me/p5NRQ8-lf. 42 | -------------------------------------------------------------------------------- /AppInventor/mqtt_appinventor.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | MQTT JavaScript Client Example 5 | 6 | 7 | 8 | 9 |
ESP8266 MQTT Server

10 |
11 |

12 | Request:
13 | 14 | 15 |

16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 100 | 101 | 102 | -------------------------------------------------------------------------------- /AppInventor_CfgMQTT/AppInventor_MQTT_CFG.aia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/internetofhomethings/Configurable-Web-Server/38879014a7db6cd5804a302e143d954b3d22765b/AppInventor_CfgMQTT/AppInventor_MQTT_CFG.aia -------------------------------------------------------------------------------- /AppInventor_CfgMQTT/AppInventor_MQTT_CFG.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/internetofhomethings/Configurable-Web-Server/38879014a7db6cd5804a302e143d954b3d22765b/AppInventor_CfgMQTT/AppInventor_MQTT_CFG.apk -------------------------------------------------------------------------------- /AppInventor_CfgMQTT/README.md: -------------------------------------------------------------------------------- 1 |

AppInventor Android App MQTT Example

2 | 3 | This project is an Android Application developoed using App Inventor. 4 | It is provided as an example method to interface with an MQTT broker. 5 | 6 | How it works: 7 | 8 | The App Inventor communicates with an html/JavaScript webpage using 9 | the WebViewString. WebViewString is visible to both App Inventor and JavaScript. 10 | 11 | The MQTT parameters are now configurable using this App Inventor App. The initial 12 | default values are: 13 | 14 | broker: "ws://test.mosquitto.org:8080/mqtt";
15 | request topic: "MyMqttSvrRqst";
16 | reply topic: "MyMqttSvrRply";
17 | 18 | These values will work only with the project presented here. They will need to be 19 | modified as necessary to meet your own system requirements 20 | 21 |

Setup:

22 | 23 | 1. Connect your Android device to a PC via USB. 24 | 2. From the PC, copy the file mqtt_appinventor.html to your Android SD card at the following location:

25 | \Phone\mqtt\mqtt_appinventor.html

26 | 3. Install the application "AppInventor_MQTT_CFG.apk" on the Android device. 27 | 28 | NOTE: If you want to build your own Android Application using the App Inventor web interface, 29 | import the project file AppInventor_MQTT_CFG.aia. 30 | 31 | This App assumes an ESP8266 device is running with the sketch found at 32 | 33 | https://github.com/internetofhomethings/Configurable-Web-Server 34 | 35 | installed. 36 | -------------------------------------------------------------------------------- /AppInventor_CfgMQTT/cfg.txt: -------------------------------------------------------------------------------- 1 | { 2 | "mqtt_broker":"ws://test.mosquitto.org:8080/mqtt", 3 | "mqtt_txtopic":"MyMqttSvrRqst", 4 | "mqtt_rxtopic":"MyMqttSvrRply" 5 | } 6 | -------------------------------------------------------------------------------- /AppInventor_CfgMQTT/mqtt_appinventor.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | MQTT JavaScript Client Example 5 | 6 | 7 | 8 | 9 |
ESP8266 MQTT Server

10 |
11 |

12 | Request:
13 | 14 | 15 |

16 | 17 | 18 |

19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /AppInventor_CfgMQTT_TLS/AppInventor_MQTT_CFG_TLS.aia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/internetofhomethings/Configurable-Web-Server/38879014a7db6cd5804a302e143d954b3d22765b/AppInventor_CfgMQTT_TLS/AppInventor_MQTT_CFG_TLS.aia -------------------------------------------------------------------------------- /AppInventor_CfgMQTT_TLS/AppInventor_MQTT_CFG_TLS.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/internetofhomethings/Configurable-Web-Server/38879014a7db6cd5804a302e143d954b3d22765b/AppInventor_CfgMQTT_TLS/AppInventor_MQTT_CFG_TLS.apk -------------------------------------------------------------------------------- /AppInventor_CfgMQTT_TLS/README.md: -------------------------------------------------------------------------------- 1 |

AppInventor Android App MQTT Example

2 | 3 | This project is an Android Application developoed using App Inventor. 4 | It is provided as an example method to interface with an MQTT broker. 5 | 6 | How it works: 7 | 8 | The App Inventor communicates with an html/JavaScript webpage using 9 | the WebViewString. WebViewString is visible to both App Inventor and JavaScript. 10 | 11 | The MQTT parameters are now configurable using this App Inventor App. The initial 12 | default values are: 13 | 14 | broker: "broker.mqttdashboard.com";
15 | request topic: "mqtt_request";
16 | reply topic: "mqtt_reply";
17 | user name: "mosquitto";
18 | password: "mosquitto";
19 | reply topic: "mqtt_reply";
20 | connect port: "8000";
21 | connect clientID: "clientID";
22 | keepalive timeout: "60";
23 | last will topic: "closing down....";
24 | last will message: "lwt";
25 | last will QoS: "0";
26 | TLS connect enable: "true";
27 | 28 | These values will only work with the project presented here. This example broker will only 29 | support non-TLS connections. You will need to use a broker that supports secure TLS websockets 30 | to utilize that feature. These values will need to be modified as necessary to meet your 31 | own system requirements. 32 | 33 |

Setup:

34 | 35 | 1. Connect your Android device to a PC via USB. 36 | 2. From the PC, copy the following files to your Android SD card at the following location:

37 | \Phone\mqtt\mqtt_appinventor_paho.html
38 | \Phone\mqtt\mqttws31.js
39 | \Phone\mqtt\cfg.txt

40 | 3. Install the application "AppInventor_MQTT_CFG_TLS.apk" on the Android device. 41 | 42 | NOTE: If you want to build your own Android Application using the App Inventor web interface, 43 | import the project file AppInventor_MQTT_CFG_TLS.aia. 44 | 45 | This App assumes an ESP8266 device is running with the sketch found at 46 | 47 | https://github.com/internetofhomethings/Configurable-Web-Server 48 | 49 | installed. 50 | -------------------------------------------------------------------------------- /AppInventor_CfgMQTT_TLS/cfg.txt: -------------------------------------------------------------------------------- 1 | { 2 | "mqtt_broker":"broker.mqttdashboard.com", 3 | "mqtt_txtopic":"mqtt_request", 4 | "mqtt_rxtopic":"mqtt_reply", 5 | "mqtt_un":"mosquitto", 6 | "mqtt_pw":"mosquitto", 7 | "mqtt_port":"8000", 8 | "mqtt_clientId":"clientID", 9 | "mqtt_keepalive":"60", 10 | "mqtt_lastWillTopic":"lwt", 11 | "mqtt_lastWillMessage":"closing down....", 12 | "mqtt_lastWillQoS":"0", 13 | "mqtt_TLS_enable":"false" 14 | } 15 | -------------------------------------------------------------------------------- /AppInventor_CfgMQTT_TLS/mqtt_appinventor_paho.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | MQTT JavaScript Client Example 5 | 6 | 7 | 8 |
ESP8266 MQTT Server

9 |
10 |

11 | Request:
12 | 13 | 14 |

15 | 16 | 17 |

18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 211 | 212 | 213 | -------------------------------------------------------------------------------- /AppInventor_CfgMQTT_rev1/AppInventor_MQTT_CFG_rev1.aia: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/internetofhomethings/Configurable-Web-Server/38879014a7db6cd5804a302e143d954b3d22765b/AppInventor_CfgMQTT_rev1/AppInventor_MQTT_CFG_rev1.aia -------------------------------------------------------------------------------- /AppInventor_CfgMQTT_rev1/AppInventor_MQTT_CFG_rev1.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/internetofhomethings/Configurable-Web-Server/38879014a7db6cd5804a302e143d954b3d22765b/AppInventor_CfgMQTT_rev1/AppInventor_MQTT_CFG_rev1.apk -------------------------------------------------------------------------------- /AppInventor_CfgMQTT_rev1/README.md: -------------------------------------------------------------------------------- 1 |

AppInventor Android App MQTT Example

2 | 3 | This project is an Android Application developoed using App Inventor. 4 | It is provided as an example method to interface with an MQTT broker. 5 | 6 | How it works: 7 | 8 | The App Inventor communicates with an html/JavaScript webpage using 9 | the WebViewString. WebViewString is visible to both App Inventor and JavaScript. 10 | 11 | The MQTT parameters are now configurable using this App Inventor App. The initial 12 | default values are: 13 | 14 | broker: "broker.mqttdashboard.com";
15 | request topic: "mqtt_request";
16 | reply topic: "mqtt_reply";
17 | user name: "mosquitto";
18 | password: "mosquitto";
19 | reply topic: "mqtt_reply";
20 | connect port: "8000";
21 | connect clientID: "clientID";
22 | keepalive timeout:"60";
23 | last will topic: "closing down....";
24 | last will message:"lwt";
25 | last will QoS: "0";
26 | 27 | These values will only work with the project presented here. They will need to be 28 | modified as necessary to meet your own system requirements 29 | 30 |

Setup:

31 | 32 | 1. Connect your Android device to a PC via USB. 33 | 2. From the PC, copy the following files to your Android SD card at the following location:

34 | \Phone\mqtt\mqtt_appinventor_paho.html
35 | \Phone\mqtt\mqttws31.js
36 | \Phone\mqtt\cfg.txt

37 | 3. Install the application "AppInventor_MQTT_CFG_rev1.apk" on the Android device. 38 | 39 | NOTE: If you want to build your own Android Application using the App Inventor web interface, 40 | import the project file AppInventor_MQTT_CFG_rev1.aia. 41 | 42 | This App assumes an ESP8266 device is running with the sketch found at 43 | 44 | https://github.com/internetofhomethings/Configurable-Web-Server 45 | 46 | installed. 47 | -------------------------------------------------------------------------------- /AppInventor_CfgMQTT_rev1/cfg.txt: -------------------------------------------------------------------------------- 1 | { 2 | "mqtt_broker":"broker.mqttdashboard.com", 3 | "mqtt_txtopic":"mqtt_request", 4 | "mqtt_rxtopic":"mqtt_reply", 5 | "mqtt_un":"mosquitto", 6 | "mqtt_pw":"mosquitto", 7 | "mqtt_port":"8000", 8 | "mqtt_clientId":"clientID", 9 | "mqtt_keepalive":"60", 10 | "mqtt_lastWillTopic":"lwt", 11 | "mqtt_lastWillMessage":"closing down....", 12 | "mqtt_lastWillQoS":"0" 13 | } 14 | -------------------------------------------------------------------------------- /AppInventor_CfgMQTT_rev1/mqtt_appinventor_paho.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | MQTT JavaScript Client Example 5 | 6 | 7 | 8 |
ESP8266 MQTT Server

9 |
10 |

11 | Request:
12 | 13 | 14 |

15 | 16 | 17 |

18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 209 | 210 | 211 | -------------------------------------------------------------------------------- /ArduinoHomeAutomation/ArduinoHomeAutomation.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define SERBAUD 115200 5 | #define ESPSERBAUD 1200 6 | 7 | /* 8 | The circuit: 9 | * RX is digital pin 10 (connect to TX of other device) 10 | * TX is digital pin 11 (connect to RX of other device) 11 | */ 12 | 13 | SoftwareSerial toEspSerial(10, 11); // RX, TX 14 | String fromEsp8266 = ""; 15 | String toEsp8266 = ""; 16 | String periodicMsg=""; 17 | long lastMsg = 0; 18 | 19 | // Process Requests from ESP8266 20 | void ReadAndProcessRequests() { 21 | int chan,state,button; 22 | float Ain; 23 | char szAin[20],szT[200]; 24 | button = digitalRead(6); 25 | if(button==0) { 26 | toEspSerial.println("Button has been Pressed"); 27 | } 28 | 29 | while(toEspSerial.available()) { 30 | char inChar = (char)toEspSerial.read(); // get the new byte 31 | if (inChar != '\n') { 32 | fromEsp8266 += inChar; // add it to receive string 33 | } 34 | else { // process string if end of line 35 | if(fromEsp8266.substring(0,8)=="Arduino_") { // Valid command from ESP8266? 36 | if(fromEsp8266.substring(8,10) == "SM") { // Set Digital if true 37 | // --- Build Reply String ----------------------------------------------- 38 | toEsp8266 = "Echoing your message: "; 39 | toEsp8266 += fromEsp8266.substring(10,50); 40 | // ---- Set Periodic Message String ------------------------------------- 41 | url_decode((char *)toEsp8266.c_str(), (char *)szT ); 42 | periodicMsg = szT; 43 | } 44 | else if(fromEsp8266.substring(8,10) == "SD") { // Set Digital if true 45 | // --- Build Reply String ----------------------------------------------- 46 | toEsp8266 = "Digital Channel "; 47 | toEsp8266 += fromEsp8266.substring(10,12); //Digital Channel 48 | toEsp8266 += " is "; 49 | toEsp8266 += (fromEsp8266.substring(12,13)=="0") ? "LO" : "HI"; 50 | // ---- Send Reply String ----------------------------------------------- 51 | toEspSerial.println(toEsp8266); // Send Reply String to ESP8266 52 | Serial.println(toEsp8266); // Send Reply String to Console 53 | // --- Set Digital Channel State ---------------------------------------- 54 | chan = atoi(fromEsp8266.substring(10,12).c_str()); 55 | state = atoi(fromEsp8266.substring(12,13).c_str()); 56 | digitalWrite(chan, state); // Set Digital Output per request 57 | } 58 | else if(fromEsp8266.substring(8,10) == "GD") { // Get Digital if true 59 | // --- Get Digital Channel State ---------------------------------------- 60 | chan = atoi(fromEsp8266.substring(10,12).c_str()); 61 | state = digitalRead(chan); // Set Digital Output per request 62 | // --- Build Reply String ----------------------------------------------- 63 | toEsp8266 = "Digital Channel "; 64 | toEsp8266 += fromEsp8266.substring(10,12); //Digital Channel 65 | toEsp8266 += " is "; 66 | toEsp8266 += (state==0) ? "LO" : "HI"; 67 | // ---- Send Reply String ----------------------------------------------- 68 | toEspSerial.println(toEsp8266); // Send Reply String to ESP8266 69 | Serial.println(toEsp8266); // Send Reply String to Console 70 | } 71 | else if(fromEsp8266.substring(8,10) == "GA") { // Get Analog if true 72 | // --- Get Analog Channel Reading --------------------------------------- 73 | chan = atoi(fromEsp8266.substring(10,12).c_str()); 74 | Ain = 0.0048828 * (float) analogRead(chan); // Read analog input 75 | ftoa(Ain,szAin, 2); 76 | // --- Build Reply String ----------------------------------------------- 77 | toEsp8266 = "Analog Channel "; 78 | toEsp8266 += fromEsp8266.substring(10,12); //Analog Channel 79 | toEsp8266 += " is "; 80 | toEsp8266 += String(szAin); 81 | // ---- Send Reply String ----------------------------------------------- 82 | toEspSerial.println(toEsp8266); // Send Reply String to ESP8266 83 | Serial.println(toEsp8266); // Send Reply String to Console 84 | } 85 | else { 86 | // ---- Send Reply String ----------------------------------------------- 87 | toEsp8266 = "Arduino does not recognize request."; 88 | toEspSerial.println(toEsp8266); // Send Reply String to ESP8266 89 | Serial.println(toEsp8266); // Send Reply String to Console 90 | } 91 | } 92 | fromEsp8266 = ""; 93 | toEspSerial.flush(); 94 | } 95 | } 96 | } 97 | 98 | /******************************************************** 99 | * URL Message Decoder 100 | ********************************************************/ 101 | 102 | int url_decode(char *encoded_str, char *decoded_str) { 103 | 104 | // While we're not at the end of the string (current character not NULL) 105 | while (*encoded_str) { 106 | // Check to see if the current character is a % 107 | if (*encoded_str == '%') { 108 | 109 | // Grab the next two characters and move encoded_str forwards 110 | encoded_str++; 111 | char high = *encoded_str; 112 | encoded_str++; 113 | char low = *encoded_str; 114 | 115 | // Convert ASCII 0-9A-F to a value 0-15 116 | if (high > 0x39) high -= 7; 117 | high &= 0x0f; 118 | 119 | // Same again for the low byte: 120 | if (low > 0x39) low -= 7; 121 | low &= 0x0f; 122 | 123 | // Combine the two into a single byte and store in decoded_str: 124 | *decoded_str = (high << 4) | low; 125 | } else { 126 | // All other characters copy verbatim 127 | *decoded_str = *encoded_str; 128 | } 129 | 130 | // Move both pointers to the next character: 131 | encoded_str++; 132 | decoded_str++; 133 | } 134 | // Terminate the new string with a NULL character to trim it off 135 | *decoded_str = 0; 136 | } 137 | /***************************************************** 138 | * Send Message Every 2 seconds until Message = stop * 139 | *****************************************************/ 140 | void PeriodicMessageEcho() { 141 | String dc; 142 | if(periodicMsg!="") { 143 | //Stop sending when Msg="stop" 144 | if(periodicMsg.substring(22,26) == "stop" ) { 145 | toEspSerial.println("Msg echo terminated."); 146 | periodicMsg = ""; 147 | } 148 | // Send Message every 2 seconds 149 | else { 150 | long now = millis(); 151 | if (now - lastMsg > 2000) { 152 | toEspSerial.println(periodicMsg); 153 | lastMsg = now; 154 | } 155 | } 156 | } 157 | } 158 | 159 | 160 | void setup() { 161 | Serial.begin(SERBAUD); // Initialize serial port 162 | toEspSerial.begin(ESPSERBAUD); 163 | pinMode(4 , OUTPUT); // Set Indicator LED as output 164 | 165 | } 166 | 167 | void loop() { 168 | ReadAndProcessRequests(); 169 | PeriodicMessageEcho(); 170 | } 171 | 172 | 173 | -------------------------------------------------------------------------------- /PubSubClient/CHANGES.txt: -------------------------------------------------------------------------------- 1 | 2.3 2 | * Add publish(topic,payload,retained) function 3 | 4 | 2.2 5 | * Change code layout to match Arduino Library reqs 6 | 7 | 2.1 8 | * Add MAX_TRANSFER_SIZE def to chunk messages if needed 9 | * Reject topic/payloads that exceed MQTT_MAX_PACKET_SIZE 10 | 11 | 2.0 12 | * Add (and default to) MQTT 3.1.1 support 13 | * Fix PROGMEM handling for Intel Galileo/ESP8266 14 | * Add overloaded constructors for convenience 15 | * Add chainable setters for server/callback/client/stream 16 | * Add state function to return connack return code 17 | 18 | 1.9 19 | * Do not split MQTT packets over multiple calls to _client->write() 20 | * API change: All constructors now require an instance of Client 21 | to be passed in. 22 | * Fixed example to match 1.8 api changes - dpslwk 23 | * Added username/password support - WilHall 24 | * Added publish_P - publishes messages from PROGMEM - jobytaffey 25 | 26 | 1.8 27 | * KeepAlive interval is configurable in PubSubClient.h 28 | * Maximum packet size is configurable in PubSubClient.h 29 | * API change: Return boolean rather than int from various functions 30 | * API change: Length parameter in message callback changed 31 | from int to unsigned int 32 | * Various internal tidy-ups around types 33 | 1.7 34 | * Improved keepalive handling 35 | * Updated to the Arduino-1.0 API 36 | 1.6 37 | * Added the ability to publish a retained message 38 | 39 | 1.5 40 | * Added default constructor 41 | * Fixed compile error when used with arduino-0021 or later 42 | 43 | 1.4 44 | * Fixed connection lost handling 45 | 46 | 1.3 47 | * Fixed packet reading bug in PubSubClient.readPacket 48 | 49 | 1.2 50 | * Fixed compile error when used with arduino-0016 or later 51 | 52 | 53 | 1.1 54 | * Reduced size of library 55 | * Added support for Will messages 56 | * Clarified licensing - see LICENSE.txt 57 | 58 | 59 | 1.0 60 | * Only Quality of Service (QOS) 0 messaging is supported 61 | * The maximum message size, including header, is 128 bytes 62 | * The keepalive interval is set to 30 seconds 63 | * No support for Will messages 64 | -------------------------------------------------------------------------------- /PubSubClient/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2008-2015 Nicholas O'Leary 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 17 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 18 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 19 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 20 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /PubSubClient/README.md: -------------------------------------------------------------------------------- 1 | # Arduino Client for MQTT 2 | 3 | This library provides a client for doing simple publish/subscribe messaging with 4 | a server that supports MQTT. 5 | 6 | ## Examples 7 | 8 | The library comes with a number of example sketches. See File > Examples > PubSubClient 9 | within the Arduino application. 10 | 11 | Full API documentation is available here: http://pubsubclient.knolleary.net 12 | 13 | ## Limitations 14 | 15 | - It can only publish QoS 0 messages. It can subscribe at QoS 0 or QoS 1. 16 | - The maximum message size, including header, is **128 bytes** by default. This 17 | is configurable via `MQTT_MAX_PACKET_SIZE` in `PubSubClient.h`. 18 | - The keepalive interval is set to 15 seconds by default. This is configurable 19 | via `MQTT_KEEPALIVE` in `PubSubClient.h`. 20 | - The client uses MQTT 3.1.1 by default. It can be changed to use MQTT 3.1 by 21 | changing value of `MQTT_VERSION` in `PubSubClient.h`. 22 | 23 | 24 | ## Compatible Hardware 25 | 26 | The library uses the Arduino Ethernet Client api for interacting with the 27 | underlying network hardware. This means it Just Works with a growing number of 28 | boards and shields, including: 29 | 30 | - Arduino Ethernet 31 | - Arduino Ethernet Shield 32 | - Arduino YUN – use the included `YunClient` in place of `EthernetClient`, and 33 | be sure to do a `Bridge.begin()` first 34 | - Arduino WiFi Shield - if you want to send packets > 90 bytes with this shield, 35 | enable the `MQTT_MAX_TRANSFER_SIZE` define in `PubSubClient.h`. 36 | - Sparkfun WiFly Shield – [library](https://github.com/dpslwk/WiFly) 37 | - TI CC3000 WiFi - [library](https://github.com/sparkfun/SFE_CC3000_Library) 38 | - Intel Galileo/Edison 39 | - ESP8266 40 | 41 | The library cannot currently be used with hardware based on the ENC28J60 chip – 42 | such as the Nanode or the Nuelectronics Ethernet Shield. For those, there is an 43 | [alternative library](https://github.com/njh/NanodeMQTT) available. 44 | 45 | ## License 46 | 47 | This code is released under the MIT License. 48 | -------------------------------------------------------------------------------- /PubSubClient/examples/mqtt_auth/mqtt_auth.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Basic MQTT example with Authentication 3 | 4 | - connects to an MQTT server, providing username 5 | and password 6 | - publishes "hello world" to the topic "outTopic" 7 | - subscribes to the topic "inTopic" 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | // Update these with values suitable for your network. 15 | byte mac[] = { 0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED }; 16 | IPAddress ip(172, 16, 0, 100); 17 | IPAddress server(172, 16, 0, 2); 18 | 19 | void callback(char* topic, byte* payload, unsigned int length) { 20 | // handle message arrived 21 | } 22 | 23 | EthernetClient ethClient; 24 | PubSubClient client(server, 1883, callback, ethClient); 25 | 26 | void setup() 27 | { 28 | Ethernet.begin(mac, ip); 29 | // Note - the default maximum packet size is 128 bytes. If the 30 | // combined length of clientId, username and password exceed this, 31 | // you will need to increase the value of MQTT_MAX_PACKET_SIZE in 32 | // PubSubClient.h 33 | 34 | if (client.connect("arduinoClient", "testuser", "testpass")) { 35 | client.publish("outTopic","hello world"); 36 | client.subscribe("inTopic"); 37 | } 38 | } 39 | 40 | void loop() 41 | { 42 | client.loop(); 43 | } 44 | -------------------------------------------------------------------------------- /PubSubClient/examples/mqtt_basic/mqtt_basic.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Basic MQTT example 3 | 4 | This sketch demonstrates the basic capabilities of the library. 5 | It connects to an MQTT server then: 6 | - publishes "hello world" to the topic "outTopic" 7 | - subscribes to the topic "inTopic", printing out any messages 8 | it receives. NB - it assumes the received payloads are strings not binary 9 | 10 | It will reconnect to the server if the connection is lost using a blocking 11 | reconnect function. See the 'mqtt_reconnect_nonblocking' example for how to 12 | achieve the same result without blocking the main loop. 13 | 14 | */ 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | // Update these with values suitable for your network. 21 | byte mac[] = { 0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED }; 22 | IPAddress ip(172, 16, 0, 100); 23 | IPAddress server(172, 16, 0, 2); 24 | 25 | void callback(char* topic, byte* payload, unsigned int length) { 26 | Serial.print("Message arrived ["); 27 | Serial.print(topic); 28 | Serial.print("] "); 29 | for (int i=0;i Preferences -> Additional Boards Manager URLs": 20 | http://arduino.esp8266.com/stable/package_esp8266com_index.json 21 | - Open the "Tools -> Board -> Board Manager" and click install for the ESP8266" 22 | - Select your ESP8266 in "Tools -> Board" 23 | 24 | */ 25 | 26 | #include 27 | #include 28 | 29 | // Update these with values suitable for your network. 30 | 31 | const char* ssid = "........"; 32 | const char* password = "........"; 33 | const char* mqtt_server = "broker.mqtt-dashboard.com"; 34 | 35 | WiFiClient espClient; 36 | PubSubClient client(espClient); 37 | long lastMsg = 0; 38 | char msg[50]; 39 | int value = 0; 40 | 41 | void setup() { 42 | pinMode(BUILTIN_LED, OUTPUT); // Initialize the BUILTIN_LED pin as an output 43 | Serial.begin(115200); 44 | setup_wifi(); 45 | client.setServer(mqtt_server, 1883); 46 | client.setCallback(callback); 47 | } 48 | 49 | void setup_wifi() { 50 | 51 | delay(10); 52 | // We start by connecting to a WiFi network 53 | Serial.println(); 54 | Serial.print("Connecting to "); 55 | Serial.println(ssid); 56 | 57 | WiFi.begin(ssid, password); 58 | 59 | while (WiFi.status() != WL_CONNECTED) { 60 | delay(500); 61 | Serial.print("."); 62 | } 63 | 64 | Serial.println(""); 65 | Serial.println("WiFi connected"); 66 | Serial.println("IP address: "); 67 | Serial.println(WiFi.localIP()); 68 | } 69 | 70 | void callback(char* topic, byte* payload, unsigned int length) { 71 | Serial.print("Message arrived ["); 72 | Serial.print(topic); 73 | Serial.print("] "); 74 | for (int i = 0; i < length; i++) { 75 | Serial.print((char)payload[i]); 76 | } 77 | Serial.println(); 78 | 79 | // Switch on the LED if an 1 was received as first character 80 | if ((char)payload[0] == '1') { 81 | digitalWrite(BUILTIN_LED, LOW); // Turn the LED on (Note that LOW is the voltage level 82 | // but actually the LED is on; this is because 83 | // it is acive low on the ESP-01) 84 | } else { 85 | digitalWrite(BUILTIN_LED, HIGH); // Turn the LED off by making the voltage HIGH 86 | } 87 | 88 | } 89 | 90 | void reconnect() { 91 | // Loop until we're reconnected 92 | while (!client.connected()) { 93 | Serial.print("Attempting MQTT connection..."); 94 | // Attempt to connect 95 | if (client.connect("ESP8266Client")) { 96 | Serial.println("connected"); 97 | // Once connected, publish an announcement... 98 | client.publish("outTopic", "hello world"); 99 | // ... and resubscribe 100 | client.subscribe("inTopic"); 101 | } else { 102 | Serial.print("failed, rc="); 103 | Serial.print(client.state()); 104 | Serial.println(" try again in 5 seconds"); 105 | // Wait 5 seconds before retrying 106 | delay(5000); 107 | } 108 | } 109 | } 110 | void loop() { 111 | 112 | if (!client.connected()) { 113 | reconnect(); 114 | } 115 | client.loop(); 116 | 117 | long now = millis(); 118 | if (now - lastMsg > 2000) { 119 | lastMsg = now; 120 | ++value; 121 | snprintf (msg, 75, "hello world #%ld", value); 122 | Serial.print("Publish message: "); 123 | Serial.println(msg); 124 | client.publish("outTopic", msg); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /PubSubClient/examples/mqtt_publish_in_callback/mqtt_publish_in_callback.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Publishing in the callback 3 | 4 | - connects to an MQTT server 5 | - subscribes to the topic "inTopic" 6 | - when a message is received, republishes it to "outTopic" 7 | 8 | This example shows how to publish messages within the 9 | callback function. The callback function header needs to 10 | be declared before the PubSubClient constructor and the 11 | actual callback defined afterwards. 12 | This ensures the client reference in the callback function 13 | is valid. 14 | 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | 21 | // Update these with values suitable for your network. 22 | byte mac[] = { 0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED }; 23 | IPAddress ip(172, 16, 0, 100); 24 | IPAddress server(172, 16, 0, 2); 25 | 26 | // Callback function header 27 | void callback(char* topic, byte* payload, unsigned int length); 28 | 29 | EthernetClient ethClient; 30 | PubSubClient client(server, 1883, callback, ethClient); 31 | 32 | // Callback function 33 | void callback(char* topic, byte* payload, unsigned int length) { 34 | // In order to republish this payload, a copy must be made 35 | // as the orignal payload buffer will be overwritten whilst 36 | // constructing the PUBLISH packet. 37 | 38 | // Allocate the correct amount of memory for the payload copy 39 | byte* p = (byte*)malloc(length); 40 | // Copy the payload to the new buffer 41 | memcpy(p,payload,length); 42 | client.publish("outTopic", p, length); 43 | // Free the memory 44 | free(p); 45 | } 46 | 47 | void setup() 48 | { 49 | 50 | Ethernet.begin(mac, ip); 51 | if (client.connect("arduinoClient")) { 52 | client.publish("outTopic","hello world"); 53 | client.subscribe("inTopic"); 54 | } 55 | } 56 | 57 | void loop() 58 | { 59 | client.loop(); 60 | } 61 | -------------------------------------------------------------------------------- /PubSubClient/examples/mqtt_reconnect_nonblocking/mqtt_reconnect_nonblocking.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Reconnecting MQTT example - non-blocking 3 | 4 | This sketch demonstrates how to keep the client connected 5 | using a non-blocking reconnect function. If the client loses 6 | its connection, it attempts to reconnect every 5 seconds 7 | without blocking the main loop. 8 | 9 | */ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | // Update these with values suitable for your hardware/network. 16 | byte mac[] = { 0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED }; 17 | IPAddress ip(172, 16, 0, 100); 18 | IPAddress server(172, 16, 0, 2); 19 | 20 | void callback(char* topic, byte* payload, unsigned int length) { 21 | // handle message arrived 22 | } 23 | 24 | EthernetClient ethClient; 25 | PubSubClient client(ethClient); 26 | 27 | long lastReconnectAttempt = 0; 28 | 29 | boolean reconnect() { 30 | if (client.connect("arduinoClient")) { 31 | // Once connected, publish an announcement... 32 | client.publish("outTopic","hello world"); 33 | // ... and resubscribe 34 | client.subscribe("inTopic"); 35 | } 36 | return client.connected(); 37 | } 38 | 39 | void setup() 40 | { 41 | client.setServer(server, 1883); 42 | client.setCallback(callback); 43 | 44 | Ethernet.begin(mac, ip); 45 | delay(1500); 46 | lastReconnectAttempt = 0; 47 | } 48 | 49 | 50 | void loop() 51 | { 52 | if (!client.connected()) { 53 | long now = millis(); 54 | if (now - lastReconnectAttempt > 5000) { 55 | lastReconnectAttempt = now; 56 | // Attempt to reconnect 57 | if (reconnect()) { 58 | lastReconnectAttempt = 0; 59 | } 60 | } 61 | } else { 62 | // Client connected 63 | 64 | client.loop(); 65 | } 66 | 67 | } 68 | -------------------------------------------------------------------------------- /PubSubClient/examples/mqtt_stream/mqtt_stream.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Example of using a Stream object to store the message payload 3 | 4 | Uses SRAM library: https://github.com/ennui2342/arduino-sram 5 | but could use any Stream based class such as SD 6 | 7 | - connects to an MQTT server 8 | - publishes "hello world" to the topic "outTopic" 9 | - subscribes to the topic "inTopic" 10 | */ 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | // Update these with values suitable for your network. 18 | byte mac[] = { 0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED }; 19 | IPAddress ip(172, 16, 0, 100); 20 | IPAddress server(172, 16, 0, 2); 21 | 22 | SRAM sram(4, SRAM_1024); 23 | 24 | void callback(char* topic, byte* payload, unsigned int length) { 25 | sram.seek(1); 26 | 27 | // do something with the message 28 | for(uint8_t i=0; i 4 | maintainer=Nick O'Leary 5 | sentence=A client library for MQTT messaging. 6 | paragraph=MQTT is a lightweight messaging protocol ideal for small devices. This library allows you to send and receive MQTT messages. It supports the latest MQTT 3.1.1 protocol and can be configured to use the older MQTT 3.1 if needed. It supports all Arduino Ethernet Client compatible hardware, including the Intel Galileo/Edison, ESP8266 and TI CC3000. 7 | category=Communication 8 | url=http://pubsubclient.knolleary.net 9 | architectures=* 10 | -------------------------------------------------------------------------------- /PubSubClient/src/PubSubClient.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | PubSubClient.cpp - A simple client for MQTT. 3 | Nick O'Leary 4 | http://knolleary.net 5 | */ 6 | 7 | #include "PubSubClient.h" 8 | #include "Arduino.h" 9 | 10 | PubSubClient::PubSubClient() { 11 | this->_state = MQTT_DISCONNECTED; 12 | this->_client = NULL; 13 | this->stream = NULL; 14 | setCallback(NULL); 15 | } 16 | 17 | PubSubClient::PubSubClient(Client& client) { 18 | this->_state = MQTT_DISCONNECTED; 19 | setClient(client); 20 | this->stream = NULL; 21 | } 22 | 23 | PubSubClient::PubSubClient(IPAddress addr, uint16_t port, Client& client) { 24 | this->_state = MQTT_DISCONNECTED; 25 | setServer(addr, port); 26 | setClient(client); 27 | this->stream = NULL; 28 | } 29 | PubSubClient::PubSubClient(IPAddress addr, uint16_t port, Client& client, Stream& stream) { 30 | this->_state = MQTT_DISCONNECTED; 31 | setServer(addr,port); 32 | setClient(client); 33 | setStream(stream); 34 | } 35 | PubSubClient::PubSubClient(IPAddress addr, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client) { 36 | this->_state = MQTT_DISCONNECTED; 37 | setServer(addr, port); 38 | setCallback(callback); 39 | setClient(client); 40 | this->stream = NULL; 41 | } 42 | PubSubClient::PubSubClient(IPAddress addr, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client, Stream& stream) { 43 | this->_state = MQTT_DISCONNECTED; 44 | setServer(addr,port); 45 | setCallback(callback); 46 | setClient(client); 47 | setStream(stream); 48 | } 49 | 50 | PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, Client& client) { 51 | this->_state = MQTT_DISCONNECTED; 52 | setServer(ip, port); 53 | setClient(client); 54 | this->stream = NULL; 55 | } 56 | PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, Client& client, Stream& stream) { 57 | this->_state = MQTT_DISCONNECTED; 58 | setServer(ip,port); 59 | setClient(client); 60 | setStream(stream); 61 | } 62 | PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client) { 63 | this->_state = MQTT_DISCONNECTED; 64 | setServer(ip, port); 65 | setCallback(callback); 66 | setClient(client); 67 | this->stream = NULL; 68 | } 69 | PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client, Stream& stream) { 70 | this->_state = MQTT_DISCONNECTED; 71 | setServer(ip,port); 72 | setCallback(callback); 73 | setClient(client); 74 | setStream(stream); 75 | } 76 | 77 | PubSubClient::PubSubClient(const char* domain, uint16_t port, Client& client) { 78 | this->_state = MQTT_DISCONNECTED; 79 | setServer(domain,port); 80 | setClient(client); 81 | this->stream = NULL; 82 | } 83 | PubSubClient::PubSubClient(const char* domain, uint16_t port, Client& client, Stream& stream) { 84 | this->_state = MQTT_DISCONNECTED; 85 | setServer(domain,port); 86 | setClient(client); 87 | setStream(stream); 88 | } 89 | PubSubClient::PubSubClient(const char* domain, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client) { 90 | this->_state = MQTT_DISCONNECTED; 91 | setServer(domain,port); 92 | setCallback(callback); 93 | setClient(client); 94 | this->stream = NULL; 95 | } 96 | PubSubClient::PubSubClient(const char* domain, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client, Stream& stream) { 97 | this->_state = MQTT_DISCONNECTED; 98 | setServer(domain,port); 99 | setCallback(callback); 100 | setClient(client); 101 | setStream(stream); 102 | } 103 | 104 | boolean PubSubClient::connect(const char *id) { 105 | return connect(id,NULL,NULL,0,0,0,0); 106 | } 107 | 108 | boolean PubSubClient::connect(const char *id, const char *user, const char *pass) { 109 | return connect(id,user,pass,0,0,0,0); 110 | } 111 | 112 | boolean PubSubClient::connect(const char *id, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage) { 113 | return connect(id,NULL,NULL,willTopic,willQos,willRetain,willMessage); 114 | } 115 | 116 | boolean PubSubClient::connect(const char *id, const char *user, const char *pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage) { 117 | if (!connected()) { 118 | int result = 0; 119 | 120 | if (domain != NULL) { 121 | result = _client->connect(this->domain, this->port); 122 | } else { 123 | result = _client->connect(this->ip, this->port); 124 | } 125 | if (result) { 126 | nextMsgId = 1; 127 | // Leave room in the buffer for header and variable length field 128 | uint16_t length = 5; 129 | unsigned int j; 130 | 131 | #if MQTT_VERSION == MQTT_VERSION_3_1 132 | uint8_t d[9] = {0x00,0x06,'M','Q','I','s','d','p', MQTT_VERSION}; 133 | #define MQTT_HEADER_VERSION_LENGTH 9 134 | #elif MQTT_VERSION == MQTT_VERSION_3_1_1 135 | uint8_t d[7] = {0x00,0x04,'M','Q','T','T',MQTT_VERSION}; 136 | #define MQTT_HEADER_VERSION_LENGTH 7 137 | #endif 138 | for (j = 0;j>1); 154 | } 155 | } 156 | 157 | buffer[length++] = v; 158 | 159 | buffer[length++] = ((MQTT_KEEPALIVE) >> 8); 160 | buffer[length++] = ((MQTT_KEEPALIVE) & 0xFF); 161 | length = writeString(id,buffer,length); 162 | if (willTopic) { 163 | length = writeString(willTopic,buffer,length); 164 | length = writeString(willMessage,buffer,length); 165 | } 166 | 167 | if(user != NULL) { 168 | length = writeString(user,buffer,length); 169 | if(pass != NULL) { 170 | length = writeString(pass,buffer,length); 171 | } 172 | } 173 | 174 | write(MQTTCONNECT,buffer,length-5); 175 | 176 | lastInActivity = lastOutActivity = millis(); 177 | 178 | while (!_client->available()) { 179 | unsigned long t = millis(); 180 | if (t-lastInActivity > MQTT_KEEPALIVE*1000UL) { 181 | _state = MQTT_CONNECTION_TIMEOUT; 182 | _client->stop(); 183 | return false; 184 | } 185 | } 186 | uint8_t llen; 187 | uint16_t len = readPacket(&llen); 188 | 189 | if (len == 4) { 190 | if (buffer[3] == 0) { 191 | lastInActivity = millis(); 192 | pingOutstanding = false; 193 | _state = MQTT_CONNECTED; 194 | return true; 195 | } else { 196 | _state = buffer[3]; 197 | } 198 | } 199 | _client->stop(); 200 | } else { 201 | _state = MQTT_CONNECT_FAILED; 202 | } 203 | return false; 204 | } 205 | return true; 206 | } 207 | 208 | uint8_t PubSubClient::readByte() { 209 | while(!_client->available()) {} 210 | return _client->read(); 211 | } 212 | 213 | uint16_t PubSubClient::readPacket(uint8_t* lengthLength) { 214 | uint16_t len = 0; 215 | buffer[len++] = readByte(); 216 | bool isPublish = (buffer[0]&0xF0) == MQTTPUBLISH; 217 | uint32_t multiplier = 1; 218 | uint16_t length = 0; 219 | uint8_t digit = 0; 220 | uint16_t skip = 0; 221 | uint8_t start = 0; 222 | 223 | do { 224 | digit = readByte(); 225 | buffer[len++] = digit; 226 | length += (digit & 127) * multiplier; 227 | multiplier *= 128; 228 | } while ((digit & 128) != 0); 229 | *lengthLength = len-1; 230 | 231 | if (isPublish) { 232 | // Read in topic length to calculate bytes to skip over for Stream writing 233 | buffer[len++] = readByte(); 234 | buffer[len++] = readByte(); 235 | skip = (buffer[*lengthLength+1]<<8)+buffer[*lengthLength+2]; 236 | start = 2; 237 | if (buffer[0]&MQTTQOS1) { 238 | // skip message id 239 | skip += 2; 240 | } 241 | } 242 | 243 | for (uint16_t i = start;istream) { 246 | if (isPublish && len-*lengthLength-2>skip) { 247 | this->stream->write(digit); 248 | } 249 | } 250 | if (len < MQTT_MAX_PACKET_SIZE) { 251 | buffer[len] = digit; 252 | } 253 | len++; 254 | } 255 | 256 | if (!this->stream && len > MQTT_MAX_PACKET_SIZE) { 257 | len = 0; // This will cause the packet to be ignored. 258 | } 259 | 260 | return len; 261 | } 262 | 263 | boolean PubSubClient::loop() { 264 | if (connected()) { 265 | unsigned long t = millis(); 266 | if ((t - lastInActivity > MQTT_KEEPALIVE*1000UL) || (t - lastOutActivity > MQTT_KEEPALIVE*1000UL)) { 267 | if (pingOutstanding) { 268 | this->_state = MQTT_CONNECTION_TIMEOUT; 269 | _client->stop(); 270 | return false; 271 | } else { 272 | buffer[0] = MQTTPINGREQ; 273 | buffer[1] = 0; 274 | _client->write(buffer,2); 275 | lastOutActivity = t; 276 | lastInActivity = t; 277 | pingOutstanding = true; 278 | } 279 | } 280 | if (_client->available()) { 281 | uint8_t llen; 282 | uint16_t len = readPacket(&llen); 283 | uint16_t msgId = 0; 284 | uint8_t *payload; 285 | if (len > 0) { 286 | lastInActivity = t; 287 | uint8_t type = buffer[0]&0xF0; 288 | if (type == MQTTPUBLISH) { 289 | if (callback) { 290 | uint16_t tl = (buffer[llen+1]<<8)+buffer[llen+2]; 291 | char topic[tl+1]; 292 | for (uint16_t i=0;i0 297 | if ((buffer[0]&0x06) == MQTTQOS1) { 298 | msgId = (buffer[llen+3+tl]<<8)+buffer[llen+3+tl+1]; 299 | payload = buffer+llen+3+tl+2; 300 | callback(topic,payload,len-llen-3-tl-2); 301 | 302 | buffer[0] = MQTTPUBACK; 303 | buffer[1] = 2; 304 | buffer[2] = (msgId >> 8); 305 | buffer[3] = (msgId & 0xFF); 306 | _client->write(buffer,4); 307 | lastOutActivity = t; 308 | 309 | } else { 310 | payload = buffer+llen+3+tl; 311 | callback(topic,payload,len-llen-3-tl); 312 | } 313 | } 314 | } else if (type == MQTTPINGREQ) { 315 | buffer[0] = MQTTPINGRESP; 316 | buffer[1] = 0; 317 | _client->write(buffer,2); 318 | } else if (type == MQTTPINGRESP) { 319 | pingOutstanding = false; 320 | } 321 | } 322 | } 323 | return true; 324 | } 325 | return false; 326 | } 327 | 328 | boolean PubSubClient::publish(const char* topic, const char* payload) { 329 | return publish(topic,(const uint8_t*)payload,strlen(payload),false); 330 | } 331 | 332 | boolean PubSubClient::publish(const char* topic, const char* payload, boolean retained) { 333 | return publish(topic,(const uint8_t*)payload,strlen(payload),retained); 334 | } 335 | 336 | boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigned int plength) { 337 | return publish(topic, payload, plength, false); 338 | } 339 | 340 | boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigned int plength, boolean retained) { 341 | if (connected()) { 342 | if (MQTT_MAX_PACKET_SIZE < 5 + 2+strlen(topic) + plength) { 343 | // Too long 344 | return false; 345 | } 346 | // Leave room in the buffer for header and variable length field 347 | uint16_t length = 5; 348 | length = writeString(topic,buffer,length); 349 | uint16_t i; 350 | for (i=0;i 0) { 388 | digit |= 0x80; 389 | } 390 | buffer[pos++] = digit; 391 | llen++; 392 | } while(len>0); 393 | 394 | pos = writeString(topic,buffer,pos); 395 | 396 | rc += _client->write(buffer,pos); 397 | 398 | for (i=0;iwrite((char)pgm_read_byte_near(payload + i)); 400 | } 401 | 402 | lastOutActivity = millis(); 403 | 404 | return rc == tlen + 4 + plength; 405 | } 406 | 407 | boolean PubSubClient::write(uint8_t header, uint8_t* buf, uint16_t length) { 408 | uint8_t lenBuf[4]; 409 | uint8_t llen = 0; 410 | uint8_t digit; 411 | uint8_t pos = 0; 412 | uint8_t rc; 413 | uint16_t len = length; 414 | do { 415 | digit = len % 128; 416 | len = len / 128; 417 | if (len > 0) { 418 | digit |= 0x80; 419 | } 420 | lenBuf[pos++] = digit; 421 | llen++; 422 | } while(len>0); 423 | 424 | buf[4-llen] = header; 425 | for (int i=0;i 0) && result) { 435 | bytesToWrite = (bytesRemaining > MQTT_MAX_TRANSFER_SIZE)?MQTT_MAX_TRANSFER_SIZE:bytesRemaining; 436 | rc = _client->write(writeBuf,bytesToWrite); 437 | result = (rc == bytesToWrite); 438 | bytesRemaining -= rc; 439 | writeBuf += rc; 440 | } 441 | return result; 442 | #else 443 | rc = _client->write(buf+(4-llen),length+1+llen); 444 | lastOutActivity = millis(); 445 | return (rc == 1+llen+length); 446 | #endif 447 | } 448 | 449 | boolean PubSubClient::subscribe(const char* topic) { 450 | return subscribe(topic, 0); 451 | } 452 | 453 | boolean PubSubClient::subscribe(const char* topic, uint8_t qos) { 454 | if (qos < 0 || qos > 1) { 455 | return false; 456 | } 457 | if (MQTT_MAX_PACKET_SIZE < 9 + strlen(topic)) { 458 | // Too long 459 | return false; 460 | } 461 | if (connected()) { 462 | // Leave room in the buffer for header and variable length field 463 | uint16_t length = 5; 464 | nextMsgId++; 465 | if (nextMsgId == 0) { 466 | nextMsgId = 1; 467 | } 468 | buffer[length++] = (nextMsgId >> 8); 469 | buffer[length++] = (nextMsgId & 0xFF); 470 | length = writeString((char*)topic, buffer,length); 471 | buffer[length++] = qos; 472 | return write(MQTTSUBSCRIBE|MQTTQOS1,buffer,length-5); 473 | } 474 | return false; 475 | } 476 | 477 | boolean PubSubClient::unsubscribe(const char* topic) { 478 | if (MQTT_MAX_PACKET_SIZE < 9 + strlen(topic)) { 479 | // Too long 480 | return false; 481 | } 482 | if (connected()) { 483 | uint16_t length = 5; 484 | nextMsgId++; 485 | if (nextMsgId == 0) { 486 | nextMsgId = 1; 487 | } 488 | buffer[length++] = (nextMsgId >> 8); 489 | buffer[length++] = (nextMsgId & 0xFF); 490 | length = writeString(topic, buffer,length); 491 | return write(MQTTUNSUBSCRIBE|MQTTQOS1,buffer,length-5); 492 | } 493 | return false; 494 | } 495 | 496 | void PubSubClient::disconnect() { 497 | buffer[0] = MQTTDISCONNECT; 498 | buffer[1] = 0; 499 | _client->write(buffer,2); 500 | _state = MQTT_DISCONNECTED; 501 | _client->stop(); 502 | lastInActivity = lastOutActivity = millis(); 503 | } 504 | 505 | uint16_t PubSubClient::writeString(const char* string, uint8_t* buf, uint16_t pos) { 506 | const char* idp = string; 507 | uint16_t i = 0; 508 | pos += 2; 509 | while (*idp) { 510 | buf[pos++] = *idp++; 511 | i++; 512 | } 513 | buf[pos-i-2] = (i >> 8); 514 | buf[pos-i-1] = (i & 0xFF); 515 | return pos; 516 | } 517 | 518 | 519 | boolean PubSubClient::connected() { 520 | boolean rc; 521 | if (_client == NULL ) { 522 | rc = false; 523 | } else { 524 | rc = (int)_client->connected(); 525 | if (!rc) { 526 | if (this->_state == MQTT_CONNECTED) { 527 | this->_state = MQTT_CONNECTION_LOST; 528 | _client->flush(); 529 | _client->stop(); 530 | } 531 | } 532 | } 533 | return rc; 534 | } 535 | 536 | PubSubClient& PubSubClient::setServer(uint8_t * ip, uint16_t port) { 537 | IPAddress addr(ip[0],ip[1],ip[2],ip[3]); 538 | return setServer(addr,port); 539 | } 540 | 541 | PubSubClient& PubSubClient::setServer(IPAddress ip, uint16_t port) { 542 | this->ip = ip; 543 | this->port = port; 544 | this->domain = NULL; 545 | return *this; 546 | } 547 | 548 | PubSubClient& PubSubClient::setServer(const char * domain, uint16_t port) { 549 | this->domain = domain; 550 | this->port = port; 551 | return *this; 552 | } 553 | 554 | PubSubClient& PubSubClient::setCallback(void(*callback)(char*,uint8_t*,unsigned int)){ 555 | this->callback = callback; 556 | return *this; 557 | } 558 | 559 | PubSubClient& PubSubClient::setClient(Client& client){ 560 | this->_client = &client; 561 | return *this; 562 | } 563 | 564 | PubSubClient& PubSubClient::setStream(Stream& stream){ 565 | this->stream = &stream; 566 | return *this; 567 | } 568 | 569 | int PubSubClient::state() { 570 | return this->_state; 571 | } 572 | -------------------------------------------------------------------------------- /PubSubClient/src/PubSubClient.h: -------------------------------------------------------------------------------- 1 | /* 2 | PubSubClient.h - A simple client for MQTT. 3 | Nick O'Leary 4 | http://knolleary.net 5 | */ 6 | 7 | #ifndef PubSubClient_h 8 | #define PubSubClient_h 9 | 10 | #include 11 | #include "IPAddress.h" 12 | #include "Client.h" 13 | #include "Stream.h" 14 | 15 | #define MQTT_VERSION_3_1 3 16 | #define MQTT_VERSION_3_1_1 4 17 | 18 | // MQTT_VERSION : Pick the version 19 | //#define MQTT_VERSION MQTT_VERSION_3_1 20 | #define MQTT_VERSION MQTT_VERSION_3_1_1 21 | 22 | // MQTT_MAX_PACKET_SIZE : Maximum packet size 23 | #define MQTT_MAX_PACKET_SIZE 256 24 | 25 | // MQTT_KEEPALIVE : keepAlive interval in Seconds 26 | #define MQTT_KEEPALIVE 15 27 | 28 | // MQTT_MAX_TRANSFER_SIZE : limit how much data is passed to the network client 29 | // in each write call. Needed for the Arduino Wifi Shield. Leave undefined to 30 | // pass the entire MQTT packet in each write call. 31 | //#define MQTT_MAX_TRANSFER_SIZE 80 32 | 33 | // Possible values for client.state() 34 | #define MQTT_CONNECTION_TIMEOUT -4 35 | #define MQTT_CONNECTION_LOST -3 36 | #define MQTT_CONNECT_FAILED -2 37 | #define MQTT_DISCONNECTED -1 38 | #define MQTT_CONNECTED 0 39 | #define MQTT_CONNECT_BAD_PROTOCOL 1 40 | #define MQTT_CONNECT_BAD_CLIENT_ID 2 41 | #define MQTT_CONNECT_UNAVAILABLE 3 42 | #define MQTT_CONNECT_BAD_CREDENTIALS 4 43 | #define MQTT_CONNECT_UNAUTHORIZED 5 44 | 45 | #define MQTTCONNECT 1 << 4 // Client request to connect to Server 46 | #define MQTTCONNACK 2 << 4 // Connect Acknowledgment 47 | #define MQTTPUBLISH 3 << 4 // Publish message 48 | #define MQTTPUBACK 4 << 4 // Publish Acknowledgment 49 | #define MQTTPUBREC 5 << 4 // Publish Received (assured delivery part 1) 50 | #define MQTTPUBREL 6 << 4 // Publish Release (assured delivery part 2) 51 | #define MQTTPUBCOMP 7 << 4 // Publish Complete (assured delivery part 3) 52 | #define MQTTSUBSCRIBE 8 << 4 // Client Subscribe request 53 | #define MQTTSUBACK 9 << 4 // Subscribe Acknowledgment 54 | #define MQTTUNSUBSCRIBE 10 << 4 // Client Unsubscribe request 55 | #define MQTTUNSUBACK 11 << 4 // Unsubscribe Acknowledgment 56 | #define MQTTPINGREQ 12 << 4 // PING Request 57 | #define MQTTPINGRESP 13 << 4 // PING Response 58 | #define MQTTDISCONNECT 14 << 4 // Client is Disconnecting 59 | #define MQTTReserved 15 << 4 // Reserved 60 | 61 | #define MQTTQOS0 (0 << 1) 62 | #define MQTTQOS1 (1 << 1) 63 | #define MQTTQOS2 (2 << 1) 64 | 65 | #define MQTT_CALLBACK_SIGNATURE void (*callback)(char*,uint8_t*,unsigned int) 66 | 67 | class PubSubClient { 68 | private: 69 | Client* _client; 70 | uint8_t buffer[MQTT_MAX_PACKET_SIZE]; 71 | uint16_t nextMsgId; 72 | unsigned long lastOutActivity; 73 | unsigned long lastInActivity; 74 | bool pingOutstanding; 75 | MQTT_CALLBACK_SIGNATURE; 76 | uint16_t readPacket(uint8_t*); 77 | uint8_t readByte(); 78 | boolean write(uint8_t header, uint8_t* buf, uint16_t length); 79 | uint16_t writeString(const char* string, uint8_t* buf, uint16_t pos); 80 | IPAddress ip; 81 | const char* domain; 82 | uint16_t port; 83 | Stream* stream; 84 | int _state; 85 | public: 86 | PubSubClient(); 87 | PubSubClient(Client& client); 88 | PubSubClient(IPAddress, uint16_t, Client& client); 89 | PubSubClient(IPAddress, uint16_t, Client& client, Stream&); 90 | PubSubClient(IPAddress, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client); 91 | PubSubClient(IPAddress, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client, Stream&); 92 | PubSubClient(uint8_t *, uint16_t, Client& client); 93 | PubSubClient(uint8_t *, uint16_t, Client& client, Stream&); 94 | PubSubClient(uint8_t *, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client); 95 | PubSubClient(uint8_t *, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client, Stream&); 96 | PubSubClient(const char*, uint16_t, Client& client); 97 | PubSubClient(const char*, uint16_t, Client& client, Stream&); 98 | PubSubClient(const char*, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client); 99 | PubSubClient(const char*, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client, Stream&); 100 | 101 | PubSubClient& setServer(IPAddress ip, uint16_t port); 102 | PubSubClient& setServer(uint8_t * ip, uint16_t port); 103 | PubSubClient& setServer(const char * domain, uint16_t port); 104 | PubSubClient& setCallback(MQTT_CALLBACK_SIGNATURE); 105 | PubSubClient& setClient(Client& client); 106 | PubSubClient& setStream(Stream& stream); 107 | 108 | boolean connect(const char* id); 109 | boolean connect(const char* id, const char* user, const char* pass); 110 | boolean connect(const char* id, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage); 111 | boolean connect(const char* id, const char* user, const char* pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage); 112 | void disconnect(); 113 | boolean publish(const char* topic, const char* payload); 114 | boolean publish(const char* topic, const char* payload, boolean retained); 115 | boolean publish(const char* topic, const uint8_t * payload, unsigned int plength); 116 | boolean publish(const char* topic, const uint8_t * payload, unsigned int plength, boolean retained); 117 | boolean publish_P(const char* topic, const uint8_t * payload, unsigned int plength, boolean retained); 118 | boolean subscribe(const char* topic); 119 | boolean subscribe(const char* topic, uint8_t qos); 120 | boolean unsubscribe(const char* topic); 121 | boolean loop(); 122 | boolean connected(); 123 | int state(); 124 | }; 125 | 126 | 127 | #endif 128 | -------------------------------------------------------------------------------- /PubSubClient/tests/Makefile: -------------------------------------------------------------------------------- 1 | SRC_PATH=./src 2 | OUT_PATH=./bin 3 | TEST_SRC=$(wildcard ${SRC_PATH}/*_spec.cpp) 4 | TEST_BIN= $(TEST_SRC:${SRC_PATH}/%.cpp=${OUT_PATH}/%) 5 | VPATH=${SRC_PATH} 6 | SHIM_FILES=${SRC_PATH}/lib/*.cpp 7 | PSC_FILE=../src/PubSubClient.cpp 8 | CC=g++ 9 | CFLAGS=-I${SRC_PATH}/lib -I../src 10 | 11 | all: $(TEST_BIN) 12 | 13 | ${OUT_PATH}/%: ${SRC_PATH}/%.cpp ${PSC_FILE} ${SHIM_FILES} 14 | mkdir -p ${OUT_PATH} 15 | ${CC} ${CFLAGS} $^ -o $@ 16 | 17 | clean: 18 | @rm -rf ${OUT_PATH} 19 | 20 | test: 21 | @bin/connect_spec 22 | @bin/publish_spec 23 | @bin/receive_spec 24 | @bin/subscribe_spec 25 | @bin/keepalive_spec 26 | -------------------------------------------------------------------------------- /PubSubClient/tests/README.md: -------------------------------------------------------------------------------- 1 | # Arduino Client for MQTT Test Suite 2 | 3 | This is a regression test suite for the `PubSubClient` library. 4 | 5 | There are two parts: 6 | 7 | - Tests that can be compiled and run on any machine 8 | - Tests that build the example sketches using the Arduino IDE 9 | 10 | 11 | It is a work-in-progress and is subject to complete refactoring as the whim takes 12 | me. 13 | 14 | 15 | ## Local tests 16 | 17 | These are a set of executables that can be run to test specific areas of functionality. 18 | They do not require a real Arduino to be attached, nor the use of the Arduino IDE. 19 | 20 | The tests include a set of mock files to stub out the parts of the Arduino environment the library 21 | depends on. 22 | 23 | ### Dependencies 24 | 25 | - g++ 26 | 27 | ### Running 28 | 29 | Build the tests using the provided `Makefile`: 30 | 31 | $ make 32 | 33 | This will create a set of executables in `./bin/`. Run each of these executables to test the corresponding functionality. 34 | 35 | *Note:* the `connect_spec` and `keepalive_spec` tests involve testing keepalive timers so naturally take a few minutes to run through. 36 | 37 | ## Arduino tests 38 | 39 | *Note:* INO Tool doesn't currently play nicely with Arduino 1.5. This has broken this test suite. 40 | 41 | Without a suitable arduino plugged in, the test suite will only check the 42 | example sketches compile cleanly against the library. 43 | 44 | With an arduino plugged in, each sketch that has a corresponding python 45 | test case is built, uploaded and then the tests run. 46 | 47 | ### Dependencies 48 | 49 | - Python 2.7+ 50 | - [INO Tool](http://inotool.org/) - this provides command-line build/upload of Arduino sketches 51 | 52 | ### Running 53 | 54 | The test suite _does not_ run an MQTT server - it is assumed to be running already. 55 | 56 | $ python testsuite.py 57 | 58 | A summary of activity is printed to the console. More comprehensive logs are written 59 | to the `logs` directory. 60 | 61 | ### What it does 62 | 63 | For each sketch in the library's `examples` directory, e.g. `mqtt_basic.ino`, the suite looks for a matching test case 64 | `testcases/mqtt_basic.py`. 65 | 66 | The test case must follow these conventions: 67 | - sub-class `unittest.TestCase` 68 | - provide the class methods `setUpClass` and `tearDownClass` (TODO: make this optional) 69 | - all test method names begin with `test_` 70 | 71 | The suite will call the `setUpClass` method _before_ uploading the sketch. This 72 | allows any test setup to be performed before the sketch runs - such as connecting 73 | a client and subscribing to topics. 74 | 75 | 76 | ### Settings 77 | 78 | The file `testcases/settings.py` is used to config the test environment. 79 | 80 | - `server_ip` - the IP address of the broker the client should connect to (the broker port is assumed to be 1883). 81 | - `arduino_ip` - the IP address the arduino should use (when not testing DHCP). 82 | 83 | Before each sketch is compiled, these values are automatically substituted in. To 84 | do this, the suite looks for lines that _start_ with the following: 85 | 86 | byte server[] = { 87 | byte ip[] = { 88 | 89 | and replaces them with the appropriate values. 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /PubSubClient/tests/src/connect_spec.cpp: -------------------------------------------------------------------------------- 1 | #include "PubSubClient.h" 2 | #include "ShimClient.h" 3 | #include "Buffer.h" 4 | #include "BDDTest.h" 5 | #include "trace.h" 6 | 7 | 8 | byte server[] = { 172, 16, 0, 2 }; 9 | 10 | void callback(char* topic, byte* payload, unsigned int length) { 11 | // handle message arrived 12 | } 13 | 14 | 15 | int test_connect_fails_no_network() { 16 | IT("fails to connect if underlying client doesn't connect"); 17 | ShimClient shimClient; 18 | shimClient.setAllowConnect(false); 19 | PubSubClient client(server, 1883, callback, shimClient); 20 | int rc = client.connect((char*)"client_test1"); 21 | IS_FALSE(rc); 22 | int state = client.state(); 23 | IS_TRUE(state == MQTT_CONNECT_FAILED); 24 | END_IT 25 | } 26 | 27 | int test_connect_fails_on_no_response() { 28 | IT("fails to connect if no response received after 15 seconds"); 29 | ShimClient shimClient; 30 | shimClient.setAllowConnect(true); 31 | PubSubClient client(server, 1883, callback, shimClient); 32 | int rc = client.connect((char*)"client_test1"); 33 | IS_FALSE(rc); 34 | int state = client.state(); 35 | IS_TRUE(state == MQTT_CONNECTION_TIMEOUT); 36 | END_IT 37 | } 38 | 39 | int test_connect_properly_formatted() { 40 | IT("sends a properly formatted connect packet and succeeds"); 41 | ShimClient shimClient; 42 | 43 | shimClient.setAllowConnect(true); 44 | byte expectServer[] = { 172, 16, 0, 2 }; 45 | shimClient.expectConnect(expectServer,1883); 46 | byte connect[] = {0x10,0x18,0x0,0x4,0x4d,0x51,0x54,0x54,0x4,0x2,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31}; 47 | byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; 48 | 49 | shimClient.expect(connect,26); 50 | shimClient.respond(connack,4); 51 | 52 | PubSubClient client(server, 1883, callback, shimClient); 53 | int state = client.state(); 54 | IS_TRUE(state == MQTT_DISCONNECTED); 55 | 56 | int rc = client.connect((char*)"client_test1"); 57 | IS_TRUE(rc); 58 | IS_FALSE(shimClient.error()); 59 | 60 | state = client.state(); 61 | IS_TRUE(state == MQTT_CONNECTED); 62 | 63 | END_IT 64 | } 65 | 66 | int test_connect_properly_formatted_hostname() { 67 | IT("accepts a hostname"); 68 | ShimClient shimClient; 69 | 70 | shimClient.setAllowConnect(true); 71 | shimClient.expectConnect((char* const)"localhost",1883); 72 | byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; 73 | shimClient.respond(connack,4); 74 | 75 | PubSubClient client((char* const)"localhost", 1883, callback, shimClient); 76 | int rc = client.connect((char*)"client_test1"); 77 | IS_TRUE(rc); 78 | IS_FALSE(shimClient.error()); 79 | 80 | END_IT 81 | } 82 | 83 | 84 | int test_connect_fails_on_bad_rc() { 85 | IT("fails to connect if a bad return code is received"); 86 | ShimClient shimClient; 87 | shimClient.setAllowConnect(true); 88 | byte connack[] = { 0x20, 0x02, 0x00, 0x01 }; 89 | shimClient.respond(connack,4); 90 | 91 | PubSubClient client(server, 1883, callback, shimClient); 92 | int rc = client.connect((char*)"client_test1"); 93 | IS_FALSE(rc); 94 | 95 | int state = client.state(); 96 | IS_TRUE(state == 0x01); 97 | 98 | END_IT 99 | } 100 | 101 | int test_connect_accepts_username_password() { 102 | IT("accepts a username and password"); 103 | ShimClient shimClient; 104 | shimClient.setAllowConnect(true); 105 | 106 | byte connect[] = { 0x10,0x24,0x0,0x4,0x4d,0x51,0x54,0x54,0x4,0xc2,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31,0x0,0x4,0x75,0x73,0x65,0x72,0x0,0x4,0x70,0x61,0x73,0x73}; 107 | byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; 108 | shimClient.expect(connect,0x26); 109 | shimClient.respond(connack,4); 110 | 111 | PubSubClient client(server, 1883, callback, shimClient); 112 | int rc = client.connect((char*)"client_test1",(char*)"user",(char*)"pass"); 113 | IS_TRUE(rc); 114 | IS_FALSE(shimClient.error()); 115 | 116 | END_IT 117 | } 118 | 119 | int test_connect_accepts_username_no_password() { 120 | IT("accepts a username but no password"); 121 | ShimClient shimClient; 122 | shimClient.setAllowConnect(true); 123 | 124 | byte connect[] = { 0x10,0x1e,0x0,0x4,0x4d,0x51,0x54,0x54,0x4,0x82,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31,0x0,0x4,0x75,0x73,0x65,0x72}; 125 | byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; 126 | shimClient.expect(connect,0x20); 127 | shimClient.respond(connack,4); 128 | 129 | PubSubClient client(server, 1883, callback, shimClient); 130 | int rc = client.connect((char*)"client_test1",(char*)"user",0); 131 | IS_TRUE(rc); 132 | IS_FALSE(shimClient.error()); 133 | 134 | END_IT 135 | } 136 | 137 | int test_connect_ignores_password_no_username() { 138 | IT("ignores a password but no username"); 139 | ShimClient shimClient; 140 | shimClient.setAllowConnect(true); 141 | 142 | byte connect[] = {0x10,0x18,0x0,0x4,0x4d,0x51,0x54,0x54,0x4,0x2,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31}; 143 | byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; 144 | shimClient.expect(connect,26); 145 | shimClient.respond(connack,4); 146 | 147 | PubSubClient client(server, 1883, callback, shimClient); 148 | int rc = client.connect((char*)"client_test1",0,(char*)"pass"); 149 | IS_TRUE(rc); 150 | IS_FALSE(shimClient.error()); 151 | 152 | END_IT 153 | } 154 | 155 | int test_connect_with_will() { 156 | IT("accepts a will"); 157 | ShimClient shimClient; 158 | shimClient.setAllowConnect(true); 159 | 160 | byte connect[] = {0x10,0x30,0x0,0x4,0x4d,0x51,0x54,0x54,0x4,0xe,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31,0x0,0x9,0x77,0x69,0x6c,0x6c,0x54,0x6f,0x70,0x69,0x63,0x0,0xb,0x77,0x69,0x6c,0x6c,0x4d,0x65,0x73,0x73,0x61,0x67,0x65}; 161 | byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; 162 | shimClient.expect(connect,0x32); 163 | shimClient.respond(connack,4); 164 | 165 | PubSubClient client(server, 1883, callback, shimClient); 166 | int rc = client.connect((char*)"client_test1",(char*)"willTopic",1,0,(char*)"willMessage"); 167 | IS_TRUE(rc); 168 | IS_FALSE(shimClient.error()); 169 | 170 | END_IT 171 | } 172 | 173 | int test_connect_with_will_username_password() { 174 | IT("accepts a will, username and password"); 175 | ShimClient shimClient; 176 | shimClient.setAllowConnect(true); 177 | 178 | byte connect[] = {0x10,0x40,0x0,0x4,0x4d,0x51,0x54,0x54,0x4,0xce,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31,0x0,0x9,0x77,0x69,0x6c,0x6c,0x54,0x6f,0x70,0x69,0x63,0x0,0xb,0x77,0x69,0x6c,0x6c,0x4d,0x65,0x73,0x73,0x61,0x67,0x65,0x0,0x4,0x75,0x73,0x65,0x72,0x0,0x8,0x70,0x61,0x73,0x73,0x77,0x6f,0x72,0x64}; 179 | byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; 180 | shimClient.expect(connect,0x42); 181 | shimClient.respond(connack,4); 182 | 183 | PubSubClient client(server, 1883, callback, shimClient); 184 | int rc = client.connect((char*)"client_test1",(char*)"user",(char*)"password",(char*)"willTopic",1,0,(char*)"willMessage"); 185 | IS_TRUE(rc); 186 | IS_FALSE(shimClient.error()); 187 | 188 | END_IT 189 | } 190 | 191 | int test_connect_disconnect_connect() { 192 | IT("connects, disconnects and connects again"); 193 | ShimClient shimClient; 194 | 195 | shimClient.setAllowConnect(true); 196 | byte expectServer[] = { 172, 16, 0, 2 }; 197 | shimClient.expectConnect(expectServer,1883); 198 | byte connect[] = {0x10,0x18,0x0,0x4,0x4d,0x51,0x54,0x54,0x4,0x2,0x0,0xf,0x0,0xc,0x63,0x6c,0x69,0x65,0x6e,0x74,0x5f,0x74,0x65,0x73,0x74,0x31}; 199 | byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; 200 | 201 | shimClient.expect(connect,26); 202 | shimClient.respond(connack,4); 203 | 204 | PubSubClient client(server, 1883, callback, shimClient); 205 | 206 | int state = client.state(); 207 | IS_TRUE(state == MQTT_DISCONNECTED); 208 | 209 | int rc = client.connect((char*)"client_test1"); 210 | IS_TRUE(rc); 211 | IS_FALSE(shimClient.error()); 212 | 213 | state = client.state(); 214 | IS_TRUE(state == MQTT_CONNECTED); 215 | 216 | byte disconnect[] = {0xE0,0x00}; 217 | shimClient.expect(disconnect,2); 218 | 219 | client.disconnect(); 220 | 221 | IS_FALSE(client.connected()); 222 | IS_FALSE(shimClient.connected()); 223 | IS_FALSE(shimClient.error()); 224 | 225 | state = client.state(); 226 | IS_TRUE(state == MQTT_DISCONNECTED); 227 | 228 | shimClient.expect(connect,28); 229 | shimClient.respond(connack,4); 230 | rc = client.connect((char*)"client_test1"); 231 | IS_TRUE(rc); 232 | IS_FALSE(shimClient.error()); 233 | state = client.state(); 234 | IS_TRUE(state == MQTT_CONNECTED); 235 | 236 | END_IT 237 | } 238 | 239 | int main() 240 | { 241 | SUITE("Connect"); 242 | test_connect_fails_no_network(); 243 | test_connect_fails_on_no_response(); 244 | 245 | test_connect_properly_formatted(); 246 | test_connect_accepts_username_password(); 247 | test_connect_fails_on_bad_rc(); 248 | test_connect_properly_formatted_hostname(); 249 | 250 | test_connect_accepts_username_no_password(); 251 | test_connect_ignores_password_no_username(); 252 | test_connect_with_will(); 253 | test_connect_with_will_username_password(); 254 | test_connect_disconnect_connect(); 255 | FINISH 256 | } 257 | -------------------------------------------------------------------------------- /PubSubClient/tests/src/keepalive_spec.cpp: -------------------------------------------------------------------------------- 1 | #include "PubSubClient.h" 2 | #include "ShimClient.h" 3 | #include "Buffer.h" 4 | #include "BDDTest.h" 5 | #include "trace.h" 6 | #include 7 | 8 | byte server[] = { 172, 16, 0, 2 }; 9 | 10 | void callback(char* topic, byte* payload, unsigned int length) { 11 | // handle message arrived 12 | } 13 | 14 | 15 | int test_keepalive_pings_idle() { 16 | IT("keeps an idle connection alive (takes 1 minute)"); 17 | 18 | ShimClient shimClient; 19 | shimClient.setAllowConnect(true); 20 | 21 | byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; 22 | shimClient.respond(connack,4); 23 | 24 | PubSubClient client(server, 1883, callback, shimClient); 25 | int rc = client.connect((char*)"client_test1"); 26 | IS_TRUE(rc); 27 | 28 | byte pingreq[] = { 0xC0,0x0 }; 29 | shimClient.expect(pingreq,2); 30 | byte pingresp[] = { 0xD0,0x0 }; 31 | shimClient.respond(pingresp,2); 32 | 33 | for (int i = 0; i < 50; i++) { 34 | sleep(1); 35 | if ( i == 15 || i == 31 || i == 47) { 36 | shimClient.expect(pingreq,2); 37 | shimClient.respond(pingresp,2); 38 | } 39 | rc = client.loop(); 40 | IS_TRUE(rc); 41 | } 42 | 43 | IS_FALSE(shimClient.error()); 44 | 45 | END_IT 46 | } 47 | 48 | int test_keepalive_pings_with_outbound_qos0() { 49 | IT("keeps a connection alive that only sends qos0 (takes 1 minute)"); 50 | 51 | ShimClient shimClient; 52 | shimClient.setAllowConnect(true); 53 | 54 | byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; 55 | shimClient.respond(connack,4); 56 | 57 | PubSubClient client(server, 1883, callback, shimClient); 58 | int rc = client.connect((char*)"client_test1"); 59 | IS_TRUE(rc); 60 | 61 | byte publish[] = {0x30,0xe,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64}; 62 | 63 | for (int i = 0; i < 50; i++) { 64 | TRACE(i<<":"); 65 | shimClient.expect(publish,16); 66 | rc = client.publish((char*)"topic",(char*)"payload"); 67 | IS_TRUE(rc); 68 | IS_FALSE(shimClient.error()); 69 | sleep(1); 70 | if ( i == 15 || i == 31 || i == 47) { 71 | byte pingreq[] = { 0xC0,0x0 }; 72 | shimClient.expect(pingreq,2); 73 | byte pingresp[] = { 0xD0,0x0 }; 74 | shimClient.respond(pingresp,2); 75 | } 76 | rc = client.loop(); 77 | IS_TRUE(rc); 78 | IS_FALSE(shimClient.error()); 79 | } 80 | 81 | END_IT 82 | } 83 | 84 | int test_keepalive_pings_with_inbound_qos0() { 85 | IT("keeps a connection alive that only receives qos0 (takes 1 minute)"); 86 | 87 | ShimClient shimClient; 88 | shimClient.setAllowConnect(true); 89 | 90 | byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; 91 | shimClient.respond(connack,4); 92 | 93 | PubSubClient client(server, 1883, callback, shimClient); 94 | int rc = client.connect((char*)"client_test1"); 95 | IS_TRUE(rc); 96 | 97 | byte publish[] = {0x30,0xe,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64}; 98 | 99 | for (int i = 0; i < 50; i++) { 100 | TRACE(i<<":"); 101 | sleep(1); 102 | if ( i == 15 || i == 31 || i == 47) { 103 | byte pingreq[] = { 0xC0,0x0 }; 104 | shimClient.expect(pingreq,2); 105 | byte pingresp[] = { 0xD0,0x0 }; 106 | shimClient.respond(pingresp,2); 107 | } 108 | shimClient.respond(publish,16); 109 | rc = client.loop(); 110 | IS_TRUE(rc); 111 | IS_FALSE(shimClient.error()); 112 | } 113 | 114 | END_IT 115 | } 116 | 117 | int test_keepalive_no_pings_inbound_qos1() { 118 | IT("does not send pings for connections with inbound qos1 (takes 1 minute)"); 119 | 120 | ShimClient shimClient; 121 | shimClient.setAllowConnect(true); 122 | 123 | byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; 124 | shimClient.respond(connack,4); 125 | 126 | PubSubClient client(server, 1883, callback, shimClient); 127 | int rc = client.connect((char*)"client_test1"); 128 | IS_TRUE(rc); 129 | 130 | byte publish[] = {0x32,0x10,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x12,0x34,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64}; 131 | byte puback[] = {0x40,0x2,0x12,0x34}; 132 | 133 | for (int i = 0; i < 50; i++) { 134 | shimClient.respond(publish,18); 135 | shimClient.expect(puback,4); 136 | sleep(1); 137 | rc = client.loop(); 138 | IS_TRUE(rc); 139 | IS_FALSE(shimClient.error()); 140 | } 141 | 142 | END_IT 143 | } 144 | 145 | int test_keepalive_disconnects_hung() { 146 | IT("disconnects a hung connection (takes 30 seconds)"); 147 | 148 | ShimClient shimClient; 149 | shimClient.setAllowConnect(true); 150 | 151 | byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; 152 | shimClient.respond(connack,4); 153 | 154 | PubSubClient client(server, 1883, callback, shimClient); 155 | int rc = client.connect((char*)"client_test1"); 156 | IS_TRUE(rc); 157 | 158 | byte pingreq[] = { 0xC0,0x0 }; 159 | shimClient.expect(pingreq,2); 160 | 161 | for (int i = 0; i < 32; i++) { 162 | sleep(1); 163 | rc = client.loop(); 164 | } 165 | IS_FALSE(rc); 166 | 167 | int state = client.state(); 168 | IS_TRUE(state == MQTT_CONNECTION_TIMEOUT); 169 | 170 | IS_FALSE(shimClient.error()); 171 | 172 | END_IT 173 | } 174 | 175 | int main() 176 | { 177 | SUITE("Keep-alive"); 178 | test_keepalive_pings_idle(); 179 | test_keepalive_pings_with_outbound_qos0(); 180 | test_keepalive_pings_with_inbound_qos0(); 181 | test_keepalive_no_pings_inbound_qos1(); 182 | test_keepalive_disconnects_hung(); 183 | 184 | FINISH 185 | } 186 | -------------------------------------------------------------------------------- /PubSubClient/tests/src/lib/Arduino.h: -------------------------------------------------------------------------------- 1 | #ifndef Arduino_h 2 | #define Arduino_h 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | extern "C"{ 11 | typedef uint8_t byte ; 12 | typedef uint8_t boolean ; 13 | 14 | /* sketch */ 15 | extern void setup( void ) ; 16 | extern void loop( void ) ; 17 | uint32_t millis( void ); 18 | } 19 | 20 | #define PROGMEM 21 | #define pgm_read_byte_near(x) *(x) 22 | 23 | #endif // Arduino_h 24 | -------------------------------------------------------------------------------- /PubSubClient/tests/src/lib/BDDTest.cpp: -------------------------------------------------------------------------------- 1 | #include "BDDTest.h" 2 | #include "trace.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | int testCount = 0; 9 | int testPasses = 0; 10 | const char* testDescription; 11 | 12 | std::list failureList; 13 | 14 | void bddtest_suite(const char* name) { 15 | LOG(name << "\n"); 16 | } 17 | 18 | int bddtest_test(const char* file, int line, const char* assertion, int result) { 19 | if (!result) { 20 | LOG("✗\n"); 21 | std::ostringstream os; 22 | os << " ! "<::iterator it = failureList.begin(); it != failureList.end(); it++) { 40 | LOG("\n"); 41 | LOG(*it); 42 | LOG("\n"); 43 | } 44 | 45 | LOG(std::dec << testPasses << "/" << testCount << " tests passed\n\n"); 46 | if (testPasses == testCount) { 47 | return 0; 48 | } 49 | return 1; 50 | } 51 | -------------------------------------------------------------------------------- /PubSubClient/tests/src/lib/BDDTest.h: -------------------------------------------------------------------------------- 1 | #ifndef bddtest_h 2 | #define bddtest_h 3 | 4 | void bddtest_suite(const char* name); 5 | int bddtest_test(const char*, int, const char*, int); 6 | void bddtest_start(const char*); 7 | void bddtest_end(); 8 | int bddtest_summary(); 9 | 10 | #define SUITE(x) { bddtest_suite(x); } 11 | #define TEST(x) { if (!bddtest_test(__FILE__, __LINE__, #x, (x))) return false; } 12 | 13 | #define IT(x) { bddtest_start(x); } 14 | #define END_IT { bddtest_end();return true;} 15 | 16 | #define FINISH { return bddtest_summary(); } 17 | 18 | #define IS_TRUE(x) TEST(x) 19 | #define IS_FALSE(x) TEST(!(x)) 20 | #define IS_EQUAL(x,y) TEST(x==y) 21 | #define IS_NOT_EQUAL(x,y) TEST(x!=y) 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /PubSubClient/tests/src/lib/Buffer.cpp: -------------------------------------------------------------------------------- 1 | #include "Buffer.h" 2 | #include "Arduino.h" 3 | 4 | Buffer::Buffer() { 5 | } 6 | 7 | Buffer::Buffer(uint8_t* buf, size_t size) { 8 | this->add(buf,size); 9 | } 10 | bool Buffer::available() { 11 | return this->pos < this->length; 12 | } 13 | 14 | uint8_t Buffer::next() { 15 | if (this->available()) { 16 | return this->buffer[this->pos++]; 17 | } 18 | return 0; 19 | } 20 | 21 | void Buffer::reset() { 22 | this->pos = 0; 23 | } 24 | 25 | void Buffer::add(uint8_t* buf, size_t size) { 26 | uint16_t i = 0; 27 | for (;ibuffer[this->length++] = buf[i]; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /PubSubClient/tests/src/lib/Buffer.h: -------------------------------------------------------------------------------- 1 | #ifndef buffer_h 2 | #define buffer_h 3 | 4 | #include "Arduino.h" 5 | 6 | class Buffer { 7 | private: 8 | uint8_t buffer[1024]; 9 | uint16_t pos; 10 | uint16_t length; 11 | 12 | public: 13 | Buffer(); 14 | Buffer(uint8_t* buf, size_t size); 15 | 16 | virtual bool available(); 17 | virtual uint8_t next(); 18 | virtual void reset(); 19 | 20 | virtual void add(uint8_t* buf, size_t size); 21 | }; 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /PubSubClient/tests/src/lib/Client.h: -------------------------------------------------------------------------------- 1 | #ifndef client_h 2 | #define client_h 3 | #include "IPAddress.h" 4 | 5 | class Client { 6 | public: 7 | virtual int connect(IPAddress ip, uint16_t port) =0; 8 | virtual int connect(const char *host, uint16_t port) =0; 9 | virtual size_t write(uint8_t) =0; 10 | virtual size_t write(const uint8_t *buf, size_t size) =0; 11 | virtual int available() = 0; 12 | virtual int read() = 0; 13 | virtual int read(uint8_t *buf, size_t size) = 0; 14 | virtual int peek() = 0; 15 | virtual void flush() = 0; 16 | virtual void stop() = 0; 17 | virtual uint8_t connected() = 0; 18 | virtual operator bool() = 0; 19 | }; 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /PubSubClient/tests/src/lib/IPAddress.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | IPAddress::IPAddress() 6 | { 7 | memset(_address, 0, sizeof(_address)); 8 | } 9 | 10 | IPAddress::IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet) 11 | { 12 | _address[0] = first_octet; 13 | _address[1] = second_octet; 14 | _address[2] = third_octet; 15 | _address[3] = fourth_octet; 16 | } 17 | 18 | IPAddress::IPAddress(uint32_t address) 19 | { 20 | memcpy(_address, &address, sizeof(_address)); 21 | } 22 | 23 | IPAddress::IPAddress(const uint8_t *address) 24 | { 25 | memcpy(_address, address, sizeof(_address)); 26 | } 27 | 28 | IPAddress& IPAddress::operator=(const uint8_t *address) 29 | { 30 | memcpy(_address, address, sizeof(_address)); 31 | return *this; 32 | } 33 | 34 | IPAddress& IPAddress::operator=(uint32_t address) 35 | { 36 | memcpy(_address, (const uint8_t *)&address, sizeof(_address)); 37 | return *this; 38 | } 39 | 40 | bool IPAddress::operator==(const uint8_t* addr) 41 | { 42 | return memcmp(addr, _address, sizeof(_address)) == 0; 43 | } 44 | 45 | -------------------------------------------------------------------------------- /PubSubClient/tests/src/lib/IPAddress.h: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * MIT License: 4 | * Copyright (c) 2011 Adrian McEwen 5 | * Permission is hereby granted, free of charge, to any person obtaining a copy 6 | * of this software and associated documentation files (the "Software"), to deal 7 | * in the Software without restriction, including without limitation the rights 8 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | * copies of the Software, and to permit persons to whom the Software is 10 | * furnished to do so, subject to the following conditions: 11 | * 12 | * The above copyright notice and this permission notice shall be included in 13 | * all copies or substantial portions of the Software. 14 | * 15 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | * THE SOFTWARE. 22 | * 23 | * adrianm@mcqn.com 1/1/2011 24 | */ 25 | 26 | #ifndef IPAddress_h 27 | #define IPAddress_h 28 | 29 | 30 | // A class to make it easier to handle and pass around IP addresses 31 | 32 | class IPAddress { 33 | private: 34 | uint8_t _address[4]; // IPv4 address 35 | // Access the raw byte array containing the address. Because this returns a pointer 36 | // to the internal structure rather than a copy of the address this function should only 37 | // be used when you know that the usage of the returned uint8_t* will be transient and not 38 | // stored. 39 | uint8_t* raw_address() { return _address; }; 40 | 41 | public: 42 | // Constructors 43 | IPAddress(); 44 | IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet); 45 | IPAddress(uint32_t address); 46 | IPAddress(const uint8_t *address); 47 | 48 | // Overloaded cast operator to allow IPAddress objects to be used where a pointer 49 | // to a four-byte uint8_t array is expected 50 | operator uint32_t() { return *((uint32_t*)_address); }; 51 | bool operator==(const IPAddress& addr) { return (*((uint32_t*)_address)) == (*((uint32_t*)addr._address)); }; 52 | bool operator==(const uint8_t* addr); 53 | 54 | // Overloaded index operator to allow getting and setting individual octets of the address 55 | uint8_t operator[](int index) const { return _address[index]; }; 56 | uint8_t& operator[](int index) { return _address[index]; }; 57 | 58 | // Overloaded copy operators to allow initialisation of IPAddress objects from other types 59 | IPAddress& operator=(const uint8_t *address); 60 | IPAddress& operator=(uint32_t address); 61 | 62 | 63 | friend class EthernetClass; 64 | friend class UDP; 65 | friend class Client; 66 | friend class Server; 67 | friend class DhcpClass; 68 | friend class DNSClient; 69 | }; 70 | 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /PubSubClient/tests/src/lib/ShimClient.cpp: -------------------------------------------------------------------------------- 1 | #include "ShimClient.h" 2 | #include "trace.h" 3 | #include 4 | #include 5 | #include 6 | 7 | extern "C" { 8 | uint32_t millis(void) { 9 | return time(0)*1000; 10 | } 11 | } 12 | 13 | ShimClient::ShimClient() { 14 | this->responseBuffer = new Buffer(); 15 | this->expectBuffer = new Buffer(); 16 | this->_allowConnect = true; 17 | this->_connected = false; 18 | this->_error = false; 19 | this->expectAnything = true; 20 | this->_received = 0; 21 | this->_expectedPort = 0; 22 | } 23 | 24 | int ShimClient::connect(IPAddress ip, uint16_t port) { 25 | if (this->_allowConnect) { 26 | this->_connected = true; 27 | } 28 | if (this->_expectedPort !=0) { 29 | // if (memcmp(ip,this->_expectedIP,4) != 0) { 30 | // TRACE( "ip mismatch\n"); 31 | // this->_error = true; 32 | // } 33 | if (port != this->_expectedPort) { 34 | TRACE( "port mismatch\n"); 35 | this->_error = true; 36 | } 37 | } 38 | return this->_connected; 39 | } 40 | int ShimClient::connect(const char *host, uint16_t port) { 41 | if (this->_allowConnect) { 42 | this->_connected = true; 43 | } 44 | if (this->_expectedPort !=0) { 45 | if (strcmp(host,this->_expectedHost) != 0) { 46 | TRACE( "host mismatch\n"); 47 | this->_error = true; 48 | } 49 | if (port != this->_expectedPort) { 50 | TRACE( "port mismatch\n"); 51 | this->_error = true; 52 | } 53 | 54 | } 55 | return this->_connected; 56 | } 57 | size_t ShimClient::write(uint8_t b) { 58 | this->_received += 1; 59 | TRACE(std::hex << (unsigned int)b); 60 | if (!this->expectAnything) { 61 | if (this->expectBuffer->available()) { 62 | uint8_t expected = this->expectBuffer->next(); 63 | if (expected != b) { 64 | this->_error = true; 65 | TRACE("!=" << (unsigned int)expected); 66 | } 67 | } else { 68 | this->_error = true; 69 | } 70 | } 71 | TRACE("\n"<< std::dec); 72 | return 1; 73 | } 74 | size_t ShimClient::write(const uint8_t *buf, size_t size) { 75 | this->_received += size; 76 | TRACE( "[" << std::dec << (unsigned int)(size) << "] "); 77 | uint16_t i=0; 78 | for (;i0) { 80 | TRACE(":"); 81 | } 82 | TRACE(std::hex << (unsigned int)(buf[i])); 83 | 84 | if (!this->expectAnything) { 85 | if (this->expectBuffer->available()) { 86 | uint8_t expected = this->expectBuffer->next(); 87 | if (expected != buf[i]) { 88 | this->_error = true; 89 | TRACE("!=" << (unsigned int)expected); 90 | } 91 | } else { 92 | this->_error = true; 93 | } 94 | } 95 | } 96 | TRACE("\n"<responseBuffer->available(); 101 | } 102 | int ShimClient::read() { return this->responseBuffer->next(); } 103 | int ShimClient::read(uint8_t *buf, size_t size) { 104 | uint16_t i = 0; 105 | for (;iread(); 107 | } 108 | return size; 109 | } 110 | int ShimClient::peek() { return 0; } 111 | void ShimClient::flush() {} 112 | void ShimClient::stop() { 113 | this->setConnected(false); 114 | } 115 | uint8_t ShimClient::connected() { return this->_connected; } 116 | ShimClient::operator bool() { return true; } 117 | 118 | 119 | ShimClient* ShimClient::respond(uint8_t *buf, size_t size) { 120 | this->responseBuffer->add(buf,size); 121 | return this; 122 | } 123 | 124 | ShimClient* ShimClient::expect(uint8_t *buf, size_t size) { 125 | this->expectAnything = false; 126 | this->expectBuffer->add(buf,size); 127 | return this; 128 | } 129 | 130 | void ShimClient::setConnected(bool b) { 131 | this->_connected = b; 132 | } 133 | void ShimClient::setAllowConnect(bool b) { 134 | this->_allowConnect = b; 135 | } 136 | 137 | bool ShimClient::error() { 138 | return this->_error; 139 | } 140 | 141 | uint16_t ShimClient::received() { 142 | return this->_received; 143 | } 144 | 145 | void ShimClient::expectConnect(IPAddress ip, uint16_t port) { 146 | this->_expectedIP = ip; 147 | this->_expectedPort = port; 148 | } 149 | 150 | void ShimClient::expectConnect(const char *host, uint16_t port) { 151 | this->_expectedHost = host; 152 | this->_expectedPort = port; 153 | } 154 | -------------------------------------------------------------------------------- /PubSubClient/tests/src/lib/ShimClient.h: -------------------------------------------------------------------------------- 1 | #ifndef shimclient_h 2 | #define shimclient_h 3 | 4 | #include "Arduino.h" 5 | #include "Client.h" 6 | #include "IPAddress.h" 7 | #include "Buffer.h" 8 | 9 | 10 | class ShimClient : public Client { 11 | private: 12 | Buffer* responseBuffer; 13 | Buffer* expectBuffer; 14 | bool _allowConnect; 15 | bool _connected; 16 | bool expectAnything; 17 | bool _error; 18 | uint16_t _received; 19 | IPAddress _expectedIP; 20 | uint16_t _expectedPort; 21 | const char* _expectedHost; 22 | 23 | public: 24 | ShimClient(); 25 | virtual int connect(IPAddress ip, uint16_t port); 26 | virtual int connect(const char *host, uint16_t port); 27 | virtual size_t write(uint8_t); 28 | virtual size_t write(const uint8_t *buf, size_t size); 29 | virtual int available(); 30 | virtual int read(); 31 | virtual int read(uint8_t *buf, size_t size); 32 | virtual int peek(); 33 | virtual void flush(); 34 | virtual void stop(); 35 | virtual uint8_t connected(); 36 | virtual operator bool(); 37 | 38 | virtual ShimClient* respond(uint8_t *buf, size_t size); 39 | virtual ShimClient* expect(uint8_t *buf, size_t size); 40 | 41 | virtual void expectConnect(IPAddress ip, uint16_t port); 42 | virtual void expectConnect(const char *host, uint16_t port); 43 | 44 | virtual uint16_t received(); 45 | virtual bool error(); 46 | 47 | virtual void setAllowConnect(bool b); 48 | virtual void setConnected(bool b); 49 | }; 50 | 51 | #endif 52 | -------------------------------------------------------------------------------- /PubSubClient/tests/src/lib/Stream.cpp: -------------------------------------------------------------------------------- 1 | #include "Stream.h" 2 | #include "trace.h" 3 | #include 4 | #include 5 | 6 | Stream::Stream() { 7 | this->expectBuffer = new Buffer(); 8 | this->_error = false; 9 | this->_written = 0; 10 | } 11 | 12 | size_t Stream::write(uint8_t b) { 13 | this->_written++; 14 | TRACE(std::hex << (unsigned int)b); 15 | if (this->expectBuffer->available()) { 16 | uint8_t expected = this->expectBuffer->next(); 17 | if (expected != b) { 18 | this->_error = true; 19 | TRACE("!=" << (unsigned int)expected); 20 | } 21 | } else { 22 | this->_error = true; 23 | } 24 | TRACE("\n"<< std::dec); 25 | return 1; 26 | } 27 | 28 | 29 | bool Stream::error() { 30 | return this->_error; 31 | } 32 | 33 | void Stream::expect(uint8_t *buf, size_t size) { 34 | this->expectBuffer->add(buf,size); 35 | } 36 | 37 | uint16_t Stream::length() { 38 | return this->_written; 39 | } 40 | -------------------------------------------------------------------------------- /PubSubClient/tests/src/lib/Stream.h: -------------------------------------------------------------------------------- 1 | #ifndef Stream_h 2 | #define Stream_h 3 | 4 | #include "Arduino.h" 5 | #include "Buffer.h" 6 | 7 | class Stream { 8 | private: 9 | Buffer* expectBuffer; 10 | bool _error; 11 | uint16_t _written; 12 | 13 | public: 14 | Stream(); 15 | virtual size_t write(uint8_t); 16 | 17 | virtual bool error(); 18 | virtual void expect(uint8_t *buf, size_t size); 19 | virtual uint16_t length(); 20 | }; 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /PubSubClient/tests/src/lib/trace.h: -------------------------------------------------------------------------------- 1 | #ifndef trace_h 2 | #define trace_h 3 | #include 4 | 5 | #include 6 | 7 | #define LOG(x) {std::cout << x << std::flush; } 8 | #define TRACE(x) {if (getenv("TRACE")) { std::cout << x << std::flush; }} 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /PubSubClient/tests/src/publish_spec.cpp: -------------------------------------------------------------------------------- 1 | #include "PubSubClient.h" 2 | #include "ShimClient.h" 3 | #include "Buffer.h" 4 | #include "BDDTest.h" 5 | #include "trace.h" 6 | 7 | 8 | byte server[] = { 172, 16, 0, 2 }; 9 | 10 | void callback(char* topic, byte* payload, unsigned int length) { 11 | // handle message arrived 12 | } 13 | 14 | int test_publish() { 15 | IT("publishes a null-terminated string"); 16 | ShimClient shimClient; 17 | shimClient.setAllowConnect(true); 18 | 19 | byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; 20 | shimClient.respond(connack,4); 21 | 22 | PubSubClient client(server, 1883, callback, shimClient); 23 | int rc = client.connect((char*)"client_test1"); 24 | IS_TRUE(rc); 25 | 26 | byte publish[] = {0x30,0xe,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64}; 27 | shimClient.expect(publish,16); 28 | 29 | rc = client.publish((char*)"topic",(char*)"payload"); 30 | IS_TRUE(rc); 31 | 32 | IS_FALSE(shimClient.error()); 33 | 34 | END_IT 35 | } 36 | 37 | 38 | int test_publish_bytes() { 39 | IT("publishes a byte array"); 40 | ShimClient shimClient; 41 | shimClient.setAllowConnect(true); 42 | 43 | byte payload[] = { 0x01,0x02,0x03,0x0,0x05 }; 44 | int length = 5; 45 | 46 | byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; 47 | shimClient.respond(connack,4); 48 | 49 | PubSubClient client(server, 1883, callback, shimClient); 50 | int rc = client.connect((char*)"client_test1"); 51 | IS_TRUE(rc); 52 | 53 | byte publish[] = {0x30,0xc,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x1,0x2,0x3,0x0,0x5}; 54 | shimClient.expect(publish,14); 55 | 56 | rc = client.publish((char*)"topic",payload,length); 57 | IS_TRUE(rc); 58 | 59 | IS_FALSE(shimClient.error()); 60 | 61 | END_IT 62 | } 63 | 64 | 65 | int test_publish_retained() { 66 | IT("publishes retained - 1"); 67 | ShimClient shimClient; 68 | shimClient.setAllowConnect(true); 69 | 70 | byte payload[] = { 0x01,0x02,0x03,0x0,0x05 }; 71 | int length = 5; 72 | 73 | byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; 74 | shimClient.respond(connack,4); 75 | 76 | PubSubClient client(server, 1883, callback, shimClient); 77 | int rc = client.connect((char*)"client_test1"); 78 | IS_TRUE(rc); 79 | 80 | byte publish[] = {0x31,0xc,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x1,0x2,0x3,0x0,0x5}; 81 | shimClient.expect(publish,14); 82 | 83 | rc = client.publish((char*)"topic",payload,length,true); 84 | IS_TRUE(rc); 85 | 86 | IS_FALSE(shimClient.error()); 87 | 88 | END_IT 89 | } 90 | 91 | int test_publish_retained_2() { 92 | IT("publishes retained - 2"); 93 | ShimClient shimClient; 94 | shimClient.setAllowConnect(true); 95 | 96 | byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; 97 | shimClient.respond(connack,4); 98 | 99 | PubSubClient client(server, 1883, callback, shimClient); 100 | int rc = client.connect((char*)"client_test1"); 101 | IS_TRUE(rc); 102 | 103 | byte publish[] = {0x31,0xc,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,'A','B','C','D','E'}; 104 | shimClient.expect(publish,14); 105 | 106 | rc = client.publish((char*)"topic",(char*)"ABCDE",true); 107 | IS_TRUE(rc); 108 | 109 | IS_FALSE(shimClient.error()); 110 | 111 | END_IT 112 | } 113 | 114 | int test_publish_not_connected() { 115 | IT("publish fails when not connected"); 116 | ShimClient shimClient; 117 | 118 | PubSubClient client(server, 1883, callback, shimClient); 119 | 120 | int rc = client.publish((char*)"topic",(char*)"payload"); 121 | IS_FALSE(rc); 122 | 123 | IS_FALSE(shimClient.error()); 124 | 125 | END_IT 126 | } 127 | 128 | int test_publish_too_long() { 129 | IT("publish fails when topic/payload are too long"); 130 | ShimClient shimClient; 131 | shimClient.setAllowConnect(true); 132 | 133 | byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; 134 | shimClient.respond(connack,4); 135 | 136 | PubSubClient client(server, 1883, callback, shimClient); 137 | int rc = client.connect((char*)"client_test1"); 138 | IS_TRUE(rc); 139 | 140 | // 0 1 2 3 4 5 6 7 8 9 0 1 2 141 | rc = client.publish((char*)"topic",(char*)"123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"); 142 | IS_FALSE(rc); 143 | 144 | IS_FALSE(shimClient.error()); 145 | 146 | END_IT 147 | } 148 | 149 | int test_publish_P() { 150 | IT("publishes using PROGMEM"); 151 | ShimClient shimClient; 152 | shimClient.setAllowConnect(true); 153 | 154 | byte payload[] = { 0x01,0x02,0x03,0x0,0x05 }; 155 | int length = 5; 156 | 157 | byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; 158 | shimClient.respond(connack,4); 159 | 160 | PubSubClient client(server, 1883, callback, shimClient); 161 | int rc = client.connect((char*)"client_test1"); 162 | IS_TRUE(rc); 163 | 164 | byte publish[] = {0x31,0xc,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x1,0x2,0x3,0x0,0x5}; 165 | shimClient.expect(publish,14); 166 | 167 | rc = client.publish_P((char*)"topic",payload,length,true); 168 | IS_TRUE(rc); 169 | 170 | IS_FALSE(shimClient.error()); 171 | 172 | END_IT 173 | } 174 | 175 | 176 | 177 | 178 | int main() 179 | { 180 | SUITE("Publish"); 181 | test_publish(); 182 | test_publish_bytes(); 183 | test_publish_retained(); 184 | test_publish_retained_2(); 185 | test_publish_not_connected(); 186 | test_publish_too_long(); 187 | test_publish_P(); 188 | 189 | FINISH 190 | } 191 | -------------------------------------------------------------------------------- /PubSubClient/tests/src/receive_spec.cpp: -------------------------------------------------------------------------------- 1 | #include "PubSubClient.h" 2 | #include "ShimClient.h" 3 | #include "Buffer.h" 4 | #include "BDDTest.h" 5 | #include "trace.h" 6 | 7 | 8 | byte server[] = { 172, 16, 0, 2 }; 9 | 10 | bool callback_called = false; 11 | char lastTopic[1024]; 12 | char lastPayload[1024]; 13 | unsigned int lastLength; 14 | 15 | void reset_callback() { 16 | callback_called = false; 17 | lastTopic[0] = '\0'; 18 | lastPayload[0] = '\0'; 19 | lastLength = 0; 20 | } 21 | 22 | void callback(char* topic, byte* payload, unsigned int length) { 23 | callback_called = true; 24 | strcpy(lastTopic,topic); 25 | memcpy(lastPayload,payload,length); 26 | lastLength = length; 27 | } 28 | 29 | int test_receive_callback() { 30 | IT("receives a callback message"); 31 | reset_callback(); 32 | 33 | ShimClient shimClient; 34 | shimClient.setAllowConnect(true); 35 | 36 | byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; 37 | shimClient.respond(connack,4); 38 | 39 | PubSubClient client(server, 1883, callback, shimClient); 40 | int rc = client.connect((char*)"client_test1"); 41 | IS_TRUE(rc); 42 | 43 | byte publish[] = {0x30,0xe,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64}; 44 | shimClient.respond(publish,16); 45 | 46 | rc = client.loop(); 47 | 48 | IS_TRUE(rc); 49 | 50 | IS_TRUE(callback_called); 51 | IS_TRUE(strcmp(lastTopic,"topic")==0); 52 | IS_TRUE(memcmp(lastPayload,"payload",7)==0); 53 | IS_TRUE(lastLength == 7); 54 | 55 | IS_FALSE(shimClient.error()); 56 | 57 | END_IT 58 | } 59 | 60 | int test_receive_stream() { 61 | IT("receives a streamed callback message"); 62 | reset_callback(); 63 | 64 | Stream stream; 65 | stream.expect((uint8_t*)"payload",7); 66 | 67 | ShimClient shimClient; 68 | shimClient.setAllowConnect(true); 69 | 70 | byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; 71 | shimClient.respond(connack,4); 72 | 73 | PubSubClient client(server, 1883, callback, shimClient, stream); 74 | int rc = client.connect((char*)"client_test1"); 75 | IS_TRUE(rc); 76 | 77 | byte publish[] = {0x30,0xe,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64}; 78 | shimClient.respond(publish,16); 79 | 80 | rc = client.loop(); 81 | 82 | IS_TRUE(rc); 83 | 84 | IS_TRUE(callback_called); 85 | IS_TRUE(strcmp(lastTopic,"topic")==0); 86 | IS_TRUE(lastLength == 7); 87 | 88 | IS_FALSE(stream.error()); 89 | IS_FALSE(shimClient.error()); 90 | 91 | END_IT 92 | } 93 | 94 | int test_receive_max_sized_message() { 95 | IT("receives an max-sized message"); 96 | reset_callback(); 97 | 98 | ShimClient shimClient; 99 | shimClient.setAllowConnect(true); 100 | 101 | byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; 102 | shimClient.respond(connack,4); 103 | 104 | PubSubClient client(server, 1883, callback, shimClient); 105 | int rc = client.connect((char*)"client_test1"); 106 | IS_TRUE(rc); 107 | 108 | int length = MQTT_MAX_PACKET_SIZE; 109 | byte publish[] = {0x30,length-2,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64}; 110 | byte bigPublish[length]; 111 | memset(bigPublish,'A',length); 112 | bigPublish[length] = 'B'; 113 | memcpy(bigPublish,publish,16); 114 | shimClient.respond(bigPublish,length); 115 | 116 | rc = client.loop(); 117 | 118 | IS_TRUE(rc); 119 | 120 | IS_TRUE(callback_called); 121 | IS_TRUE(strcmp(lastTopic,"topic")==0); 122 | IS_TRUE(lastLength == length-9); 123 | IS_TRUE(memcmp(lastPayload,bigPublish+9,lastLength)==0); 124 | 125 | IS_FALSE(shimClient.error()); 126 | 127 | END_IT 128 | } 129 | 130 | int test_receive_oversized_message() { 131 | IT("drops an oversized message"); 132 | reset_callback(); 133 | 134 | ShimClient shimClient; 135 | shimClient.setAllowConnect(true); 136 | 137 | byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; 138 | shimClient.respond(connack,4); 139 | 140 | PubSubClient client(server, 1883, callback, shimClient); 141 | int rc = client.connect((char*)"client_test1"); 142 | IS_TRUE(rc); 143 | 144 | int length = MQTT_MAX_PACKET_SIZE+1; 145 | byte publish[] = {0x30,length-2,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64}; 146 | byte bigPublish[length]; 147 | memset(bigPublish,'A',length); 148 | bigPublish[length] = 'B'; 149 | memcpy(bigPublish,publish,16); 150 | shimClient.respond(bigPublish,length); 151 | 152 | rc = client.loop(); 153 | 154 | IS_TRUE(rc); 155 | 156 | IS_FALSE(callback_called); 157 | 158 | IS_FALSE(shimClient.error()); 159 | 160 | END_IT 161 | } 162 | 163 | int test_receive_oversized_stream_message() { 164 | IT("drops an oversized message"); 165 | reset_callback(); 166 | 167 | Stream stream; 168 | 169 | ShimClient shimClient; 170 | shimClient.setAllowConnect(true); 171 | 172 | byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; 173 | shimClient.respond(connack,4); 174 | 175 | PubSubClient client(server, 1883, callback, shimClient, stream); 176 | int rc = client.connect((char*)"client_test1"); 177 | IS_TRUE(rc); 178 | 179 | int length = MQTT_MAX_PACKET_SIZE+1; 180 | byte publish[] = {0x30,length-2,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64}; 181 | 182 | byte bigPublish[length]; 183 | memset(bigPublish,'A',length); 184 | bigPublish[length] = 'B'; 185 | memcpy(bigPublish,publish,16); 186 | 187 | shimClient.respond(bigPublish,length); 188 | stream.expect(bigPublish+9,length-9); 189 | 190 | rc = client.loop(); 191 | 192 | IS_TRUE(rc); 193 | 194 | IS_TRUE(callback_called); 195 | IS_TRUE(strcmp(lastTopic,"topic")==0); 196 | IS_TRUE(lastLength == length-9); 197 | 198 | IS_FALSE(stream.error()); 199 | IS_FALSE(shimClient.error()); 200 | 201 | END_IT 202 | } 203 | 204 | int test_receive_qos1() { 205 | IT("receives a qos1 message"); 206 | reset_callback(); 207 | 208 | ShimClient shimClient; 209 | shimClient.setAllowConnect(true); 210 | 211 | byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; 212 | shimClient.respond(connack,4); 213 | 214 | PubSubClient client(server, 1883, callback, shimClient); 215 | int rc = client.connect((char*)"client_test1"); 216 | IS_TRUE(rc); 217 | 218 | byte publish[] = {0x32,0x10,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x12,0x34,0x70,0x61,0x79,0x6c,0x6f,0x61,0x64}; 219 | shimClient.respond(publish,18); 220 | 221 | byte puback[] = {0x40,0x2,0x12,0x34}; 222 | shimClient.expect(puback,4); 223 | 224 | rc = client.loop(); 225 | 226 | IS_TRUE(rc); 227 | 228 | IS_TRUE(callback_called); 229 | IS_TRUE(strcmp(lastTopic,"topic")==0); 230 | IS_TRUE(memcmp(lastPayload,"payload",7)==0); 231 | IS_TRUE(lastLength == 7); 232 | 233 | IS_FALSE(shimClient.error()); 234 | 235 | END_IT 236 | } 237 | 238 | int main() 239 | { 240 | SUITE("Receive"); 241 | test_receive_callback(); 242 | test_receive_stream(); 243 | test_receive_max_sized_message(); 244 | test_receive_oversized_message(); 245 | test_receive_oversized_stream_message(); 246 | test_receive_qos1(); 247 | 248 | FINISH 249 | } 250 | -------------------------------------------------------------------------------- /PubSubClient/tests/src/subscribe_spec.cpp: -------------------------------------------------------------------------------- 1 | #include "PubSubClient.h" 2 | #include "ShimClient.h" 3 | #include "Buffer.h" 4 | #include "BDDTest.h" 5 | #include "trace.h" 6 | 7 | 8 | byte server[] = { 172, 16, 0, 2 }; 9 | 10 | void callback(char* topic, byte* payload, unsigned int length) { 11 | // handle message arrived 12 | } 13 | 14 | int test_subscribe_no_qos() { 15 | IT("subscribe without qos defaults to 0"); 16 | ShimClient shimClient; 17 | shimClient.setAllowConnect(true); 18 | 19 | byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; 20 | shimClient.respond(connack,4); 21 | 22 | PubSubClient client(server, 1883, callback, shimClient); 23 | int rc = client.connect((char*)"client_test1"); 24 | IS_TRUE(rc); 25 | 26 | byte subscribe[] = { 0x82,0xa,0x0,0x2,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x0 }; 27 | shimClient.expect(subscribe,12); 28 | byte suback[] = { 0x90,0x3,0x0,0x2,0x0 }; 29 | shimClient.respond(suback,5); 30 | 31 | rc = client.subscribe((char*)"topic"); 32 | IS_TRUE(rc); 33 | 34 | IS_FALSE(shimClient.error()); 35 | 36 | END_IT 37 | } 38 | 39 | int test_subscribe_qos_1() { 40 | IT("subscribes qos 1"); 41 | ShimClient shimClient; 42 | shimClient.setAllowConnect(true); 43 | 44 | byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; 45 | shimClient.respond(connack,4); 46 | 47 | PubSubClient client(server, 1883, callback, shimClient); 48 | int rc = client.connect((char*)"client_test1"); 49 | IS_TRUE(rc); 50 | 51 | byte subscribe[] = { 0x82,0xa,0x0,0x2,0x0,0x5,0x74,0x6f,0x70,0x69,0x63,0x1 }; 52 | shimClient.expect(subscribe,12); 53 | byte suback[] = { 0x90,0x3,0x0,0x2,0x1 }; 54 | shimClient.respond(suback,5); 55 | 56 | rc = client.subscribe((char*)"topic",1); 57 | IS_TRUE(rc); 58 | 59 | IS_FALSE(shimClient.error()); 60 | 61 | END_IT 62 | } 63 | 64 | int test_subscribe_not_connected() { 65 | IT("subscribe fails when not connected"); 66 | ShimClient shimClient; 67 | 68 | PubSubClient client(server, 1883, callback, shimClient); 69 | 70 | int rc = client.subscribe((char*)"topic"); 71 | IS_FALSE(rc); 72 | 73 | IS_FALSE(shimClient.error()); 74 | 75 | END_IT 76 | } 77 | 78 | int test_subscribe_invalid_qos() { 79 | IT("subscribe fails with invalid qos values"); 80 | ShimClient shimClient; 81 | shimClient.setAllowConnect(true); 82 | 83 | byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; 84 | shimClient.respond(connack,4); 85 | 86 | PubSubClient client(server, 1883, callback, shimClient); 87 | int rc = client.connect((char*)"client_test1"); 88 | IS_TRUE(rc); 89 | 90 | rc = client.subscribe((char*)"topic",2); 91 | IS_FALSE(rc); 92 | rc = client.subscribe((char*)"topic",254); 93 | IS_FALSE(rc); 94 | 95 | IS_FALSE(shimClient.error()); 96 | 97 | END_IT 98 | } 99 | 100 | int test_subscribe_too_long() { 101 | IT("subscribe fails with too long topic"); 102 | ShimClient shimClient; 103 | shimClient.setAllowConnect(true); 104 | 105 | byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; 106 | shimClient.respond(connack,4); 107 | 108 | PubSubClient client(server, 1883, callback, shimClient); 109 | int rc = client.connect((char*)"client_test1"); 110 | IS_TRUE(rc); 111 | 112 | // max length should be allowed 113 | // 0 1 2 3 4 5 6 7 8 9 0 1 2 114 | rc = client.subscribe((char*)"12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"); 115 | IS_TRUE(rc); 116 | 117 | // 0 1 2 3 4 5 6 7 8 9 0 1 2 118 | rc = client.subscribe((char*)"123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"); 119 | IS_FALSE(rc); 120 | 121 | IS_FALSE(shimClient.error()); 122 | 123 | END_IT 124 | } 125 | 126 | 127 | int test_unsubscribe() { 128 | IT("unsubscribes"); 129 | ShimClient shimClient; 130 | shimClient.setAllowConnect(true); 131 | 132 | byte connack[] = { 0x20, 0x02, 0x00, 0x00 }; 133 | shimClient.respond(connack,4); 134 | 135 | PubSubClient client(server, 1883, callback, shimClient); 136 | int rc = client.connect((char*)"client_test1"); 137 | IS_TRUE(rc); 138 | 139 | byte unsubscribe[] = { 0xA2,0x9,0x0,0x2,0x0,0x5,0x74,0x6f,0x70,0x69,0x63 }; 140 | shimClient.expect(unsubscribe,12); 141 | byte unsuback[] = { 0xB0,0x2,0x0,0x2 }; 142 | shimClient.respond(unsuback,4); 143 | 144 | rc = client.unsubscribe((char*)"topic"); 145 | IS_TRUE(rc); 146 | 147 | IS_FALSE(shimClient.error()); 148 | 149 | END_IT 150 | } 151 | 152 | int test_unsubscribe_not_connected() { 153 | IT("unsubscribe fails when not connected"); 154 | ShimClient shimClient; 155 | 156 | PubSubClient client(server, 1883, callback, shimClient); 157 | 158 | int rc = client.unsubscribe((char*)"topic"); 159 | IS_FALSE(rc); 160 | 161 | IS_FALSE(shimClient.error()); 162 | 163 | END_IT 164 | } 165 | 166 | int main() 167 | { 168 | SUITE("Subscribe"); 169 | test_subscribe_no_qos(); 170 | test_subscribe_qos_1(); 171 | test_subscribe_not_connected(); 172 | test_subscribe_invalid_qos(); 173 | test_subscribe_too_long(); 174 | test_unsubscribe(); 175 | test_unsubscribe_not_connected(); 176 | FINISH 177 | } 178 | -------------------------------------------------------------------------------- /PubSubClient/tests/testcases/mqtt_basic.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import settings 3 | 4 | import time 5 | import mosquitto 6 | 7 | import serial 8 | 9 | def on_message(mosq, obj, msg): 10 | obj.message_queue.append(msg) 11 | 12 | class mqtt_basic(unittest.TestCase): 13 | 14 | message_queue = [] 15 | 16 | @classmethod 17 | def setUpClass(self): 18 | self.client = mosquitto.Mosquitto("pubsubclient_ut", clean_session=True,obj=self) 19 | self.client.connect(settings.server_ip) 20 | self.client.on_message = on_message 21 | self.client.subscribe("outTopic",0) 22 | 23 | @classmethod 24 | def tearDownClass(self): 25 | self.client.disconnect() 26 | 27 | def test_one(self): 28 | i=30 29 | while len(self.message_queue) == 0 and i > 0: 30 | self.client.loop() 31 | time.sleep(0.5) 32 | i -= 1 33 | self.assertTrue(i>0, "message receive timed-out") 34 | self.assertEqual(len(self.message_queue), 1, "unexpected number of messages received") 35 | msg = self.message_queue[0] 36 | self.assertEqual(msg.mid,0,"message id not 0") 37 | self.assertEqual(msg.topic,"outTopic","message topic incorrect") 38 | self.assertEqual(msg.payload,"hello world") 39 | self.assertEqual(msg.qos,0,"message qos not 0") 40 | self.assertEqual(msg.retain,False,"message retain flag incorrect") 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /PubSubClient/tests/testcases/mqtt_publish_in_callback.py: -------------------------------------------------------------------------------- 1 | import unittest 2 | import settings 3 | 4 | import time 5 | import mosquitto 6 | 7 | import serial 8 | 9 | def on_message(mosq, obj, msg): 10 | obj.message_queue.append(msg) 11 | 12 | class mqtt_publish_in_callback(unittest.TestCase): 13 | 14 | message_queue = [] 15 | 16 | @classmethod 17 | def setUpClass(self): 18 | self.client = mosquitto.Mosquitto("pubsubclient_ut", clean_session=True,obj=self) 19 | self.client.connect(settings.server_ip) 20 | self.client.on_message = on_message 21 | self.client.subscribe("outTopic",0) 22 | 23 | @classmethod 24 | def tearDownClass(self): 25 | self.client.disconnect() 26 | 27 | def test_connect(self): 28 | i=30 29 | while len(self.message_queue) == 0 and i > 0: 30 | self.client.loop() 31 | time.sleep(0.5) 32 | i -= 1 33 | self.assertTrue(i>0, "message receive timed-out") 34 | self.assertEqual(len(self.message_queue), 1, "unexpected number of messages received") 35 | msg = self.message_queue.pop(0) 36 | self.assertEqual(msg.mid,0,"message id not 0") 37 | self.assertEqual(msg.topic,"outTopic","message topic incorrect") 38 | self.assertEqual(msg.payload,"hello world") 39 | self.assertEqual(msg.qos,0,"message qos not 0") 40 | self.assertEqual(msg.retain,False,"message retain flag incorrect") 41 | 42 | 43 | def test_publish(self): 44 | self.assertEqual(len(self.message_queue), 0, "message queue not empty") 45 | payload = "abcdefghij" 46 | self.client.publish("inTopic",payload) 47 | 48 | i=30 49 | while len(self.message_queue) == 0 and i > 0: 50 | self.client.loop() 51 | time.sleep(0.5) 52 | i -= 1 53 | 54 | self.assertTrue(i>0, "message receive timed-out") 55 | self.assertEqual(len(self.message_queue), 1, "unexpected number of messages received") 56 | msg = self.message_queue.pop(0) 57 | self.assertEqual(msg.mid,0,"message id not 0") 58 | self.assertEqual(msg.topic,"outTopic","message topic incorrect") 59 | self.assertEqual(msg.payload,payload) 60 | self.assertEqual(msg.qos,0,"message qos not 0") 61 | self.assertEqual(msg.retain,False,"message retain flag incorrect") 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /PubSubClient/tests/testcases/settings.py: -------------------------------------------------------------------------------- 1 | server_ip = "172.16.0.2" 2 | arduino_ip = "172.16.0.100" 3 | -------------------------------------------------------------------------------- /PubSubClient/tests/testsuite.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | import os 3 | import os.path 4 | import sys 5 | import shutil 6 | from subprocess import call 7 | import importlib 8 | import unittest 9 | import re 10 | 11 | from testcases import settings 12 | 13 | class Workspace(object): 14 | 15 | def __init__(self): 16 | self.root_dir = os.getcwd() 17 | self.build_dir = os.path.join(self.root_dir,"tmpbin"); 18 | self.log_dir = os.path.join(self.root_dir,"logs"); 19 | self.tests_dir = os.path.join(self.root_dir,"testcases"); 20 | self.examples_dir = os.path.join(self.root_dir,"../PubSubClient/examples") 21 | self.examples = [] 22 | self.tests = [] 23 | if not os.path.isdir("../PubSubClient"): 24 | raise Exception("Cannot find PubSubClient library") 25 | try: 26 | import ino 27 | except: 28 | raise Exception("ino tool not installed") 29 | 30 | def init(self): 31 | if os.path.isdir(self.build_dir): 32 | shutil.rmtree(self.build_dir) 33 | os.mkdir(self.build_dir) 34 | if os.path.isdir(self.log_dir): 35 | shutil.rmtree(self.log_dir) 36 | os.mkdir(self.log_dir) 37 | 38 | os.chdir(self.build_dir) 39 | call(["ino","init"]) 40 | 41 | shutil.copytree("../../PubSubClient","lib/PubSubClient") 42 | 43 | filenames = [] 44 | for root, dirs, files in os.walk(self.examples_dir): 45 | filenames += [os.path.join(root,f) for f in files if f.endswith(".ino")] 46 | filenames.sort() 47 | for e in filenames: 48 | self.examples.append(Sketch(self,e)) 49 | 50 | filenames = [] 51 | for root, dirs, files in os.walk(self.tests_dir): 52 | filenames += [os.path.join(root,f) for f in files if f.endswith(".ino")] 53 | filenames.sort() 54 | for e in filenames: 55 | self.tests.append(Sketch(self,e)) 56 | 57 | def clean(self): 58 | shutil.rmtree(self.build_dir) 59 | 60 | class Sketch(object): 61 | def __init__(self,wksp,fn): 62 | self.w = wksp 63 | self.filename = fn 64 | self.basename = os.path.basename(self.filename) 65 | self.build_log = os.path.join(self.w.log_dir,"%s.log"%(os.path.basename(self.filename),)) 66 | self.build_err_log = os.path.join(self.w.log_dir,"%s.err.log"%(os.path.basename(self.filename),)) 67 | self.build_upload_log = os.path.join(self.w.log_dir,"%s.upload.log"%(os.path.basename(self.filename),)) 68 | 69 | def build(self): 70 | sys.stdout.write(" Build: ") 71 | sys.stdout.flush() 72 | 73 | # Copy sketch over, replacing IP addresses as necessary 74 | fin = open(self.filename,"r") 75 | lines = fin.readlines() 76 | fin.close() 77 | fout = open(os.path.join(self.w.build_dir,"src","sketch.ino"),"w") 78 | for l in lines: 79 | if re.match(r"^byte server\[\] = {",l): 80 | fout.write("byte server[] = { %s };\n"%(settings.server_ip.replace(".",", "),)) 81 | elif re.match(r"^byte ip\[\] = {",l): 82 | fout.write("byte ip[] = { %s };\n"%(settings.arduino_ip.replace(".",", "),)) 83 | else: 84 | fout.write(l) 85 | fout.flush() 86 | fout.close() 87 | 88 | # Run build 89 | fout = open(self.build_log, "w") 90 | ferr = open(self.build_err_log, "w") 91 | rc = call(["ino","build"],stdout=fout,stderr=ferr) 92 | fout.close() 93 | ferr.close() 94 | if rc == 0: 95 | sys.stdout.write("pass") 96 | sys.stdout.write("\n") 97 | return True 98 | else: 99 | sys.stdout.write("fail") 100 | sys.stdout.write("\n") 101 | with open(self.build_err_log) as f: 102 | for line in f: 103 | print " ",line, 104 | return False 105 | 106 | def upload(self): 107 | sys.stdout.write(" Upload: ") 108 | sys.stdout.flush() 109 | fout = open(self.build_upload_log, "w") 110 | rc = call(["ino","upload"],stdout=fout,stderr=fout) 111 | fout.close() 112 | if rc == 0: 113 | sys.stdout.write("pass") 114 | sys.stdout.write("\n") 115 | return True 116 | else: 117 | sys.stdout.write("fail") 118 | sys.stdout.write("\n") 119 | with open(self.build_upload_log) as f: 120 | for line in f: 121 | print " ",line, 122 | return False 123 | 124 | 125 | def test(self): 126 | # import the matching test case, if it exists 127 | try: 128 | basename = os.path.basename(self.filename)[:-4] 129 | i = importlib.import_module("testcases."+basename) 130 | except: 131 | sys.stdout.write(" Test: no tests found") 132 | sys.stdout.write("\n") 133 | return 134 | c = getattr(i,basename) 135 | 136 | testmethods = [m for m in dir(c) if m.startswith("test_")] 137 | testmethods.sort() 138 | tests = [] 139 | for m in testmethods: 140 | tests.append(c(m)) 141 | 142 | result = unittest.TestResult() 143 | c.setUpClass() 144 | if self.upload(): 145 | sys.stdout.write(" Test: ") 146 | sys.stdout.flush() 147 | for t in tests: 148 | t.run(result) 149 | print "%d/%d"%(result.testsRun-len(result.failures)-len(result.errors),result.testsRun) 150 | if not result.wasSuccessful(): 151 | if len(result.failures) > 0: 152 | for f in result.failures: 153 | print "-- %s"%(str(f[0]),) 154 | print f[1] 155 | if len(result.errors) > 0: 156 | print " Errors:" 157 | for f in result.errors: 158 | print "-- %s"%(str(f[0]),) 159 | print f[1] 160 | c.tearDownClass() 161 | 162 | if __name__ == '__main__': 163 | run_tests = True 164 | 165 | w = Workspace() 166 | w.init() 167 | 168 | for e in w.examples: 169 | print "--------------------------------------" 170 | print "[%s]"%(e.basename,) 171 | if e.build() and run_tests: 172 | e.test() 173 | for e in w.tests: 174 | print "--------------------------------------" 175 | print "[%s]"%(e.basename,) 176 | if e.build() and run_tests: 177 | e.test() 178 | 179 | w.clean() 180 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

ESP8266 http Web and MQTT Server: Update 2017-04-26

2 | 3 | In addition to the capabilities noted below, this project has been recently updated to support secure TLS connections to an MQTT broker. The revised sketch and supporting files are in the folder "http_mqtt_server_SSL". Setup is the same except the compiler directive "MQTT_SVR_ENABLE" is no longer used. 4 | 5 | This sketch was compiled using Arduino IDE 1.8.2. 6 | 7 |

ESP8266 http Web and MQTT Server: Original Release 2016-01-06

8 | 9 | This project provides a Web Server Framework supporting http and MQTT requests. 10 | 11 | Features Include: 12 | 13 | 1. ESP8266 Analog Reads (8 with multiplexer) 14 | 2. Arduino Serial Port Interface to access Analog and Digital resources 15 | 3. Webpage Configuration Control stored in ESP8266 EEPROM 16 | 17 |

Setup:

18 | 19 | 1. Copy the http_mqtt_server folder to your Arduino sketch folder. 20 | 2. Copy the UtilityFunctions folder to your Arduino libraries folder. 21 | 3. Copy the webserver folder to your Arduino libraries folder. 22 | 4. Change the following in the http_mqtt_server sketch to match your network settings: 23 | 24 |
25 | char init_ssid[32] = "YOURWIFISSID"; 26 | char init_pass[32] = "YOURWIFIPASSWORD"; 27 | //Your assigned ESP8266 static IP 28 | const char* init_ip0 = "192"; 29 | const char* init_ip1 = "168"; 30 | const char* init_ip2 = "0"; 31 | const char* init_ip3 = "132"; 32 | . 33 | //Your assigned WIFI LAN router IP 34 | const char* init_gw0 = "192"; 35 | const char* init_gw1 = "168"; 36 | const char* init_gw2 = "0"; 37 | const char* init_gw3 = "1"; 38 | . 39 | //Web Server port 40 | const char* init_port = "9701"; 41 | //Your MQTT broker 42 | const char* init_bk = "test.mosquitto.org"; 43 |
44 | 45 |

Server Setting:

46 | 47 | If you wish to disable the MQTT server, change the following in sketch.h 48 | 49 | from: 50 | 51 | define MQTT_SVR_ENABLE 1 52 | 53 | to: 54 | 55 | define MQTT_SVR_ENABLE 0 56 | 57 |

Operation:

58 | 59 | The ESP8266 performs as a server, receiving URL commands and either: 60 | 61 | 1. Sets or gets the requested ESP8266 resource and returns the appropriate reply. 62 | 2. Creates a small request string and forwards the request to an Arduino via the serial interface. 63 | 64 | In order to test this, the ESP8266 Tx needs to be connected to an Arduino Rx. 65 | Likewise, the ESP8266 Rx needs to be connected to an Arduino Tx. 66 | 67 | The subject Arduino should have the sketch "ArduinoHomeAutomation.ino" installed and running. 68 | This sketch uses the Arduino software serial interface using digital pins 10 and 11. It was 69 | tested using an Arduino nano. Using an Arduino with more serial ports, such as a MEGA can be used 70 | and utilize the built-in hardware serial port. This would require some adjustment to the sketch. 71 | 72 |

Web Server test:

73 | 74 | With both the Arduino and ESP8266 connected and running, 75 | 76 | DIGITAL CHANNEL GET: 77 | 78 | Enter the following URL in a web browser (adjust IP & port to your settings): 79 | 80 | http://192.168.0.132:9701/?arduino=GetDigital&chan=04 81 | 82 | The returned value in the web browser should be: 83 | 84 | Digital Channel 04 is LO 85 | 86 | DIGITAL CHANNEL SET: 87 | 88 | Now set the channel HI by entering the following URL: 89 | 90 | http://192.168.0.132:9701/?arduino=SetDigital&chan=04&state=1 91 | 92 | The returned value in the web browser should be: 93 | 94 | Digital Channel 04 is HI 95 | 96 | And if something is connected to channel 4, such as an LED, it should illuminate with this command. 97 | 98 | ANALOG CHANNEL GET: 99 | 100 | Enter the following URL to get the Arduino Analog channel reading: 101 | 102 | http://192.168.0.132:9701/?arduino=GetAnalog&chan=04 103 | 104 | The returned value in the web browser should be similar to (units returned are volts): 105 | 106 | Analog Channel 04 is 2.48 107 | 108 |

Expansion:

109 | 110 | Simply add the input/output configuration in your Arduino sketch setup() function to enable 111 | additional resource control such as 1-wire or i2c connected devices. 112 | 113 |

Web configuration test:

114 | 115 | This sketch is provided with the operation of loading the ESP8266 internal EEPROM with the default 116 | values hard-coded in the sketch. 117 | 118 | Once the sketch has been loaded and executed at least once, the EEPROM is set as needed. In order to 119 | disable the initialization EEPROM writes so that the EEPROM values are used, the following line 120 | in sketch.h needs to be revised: 121 | 122 | From: 123 | 124 | define EEPROM_INIT 1 125 | 126 | To: 127 | 128 | define EEPROM_INIT 0 129 | 130 | With this change, the sketch will obviously need to be reloaded into the ESP8266. 131 | 132 | This will allow configuration changes to be made using the sketch's build-in configuration webpage. 133 | 134 | In order to access the configuration screen, enter the following URL into a web browser: 135 | 136 | http://192.168.0.132:9701/config 137 | 138 | Once you have entered any desired changes, click on the SAVE button to write these new values to 139 | EEPROM, They will used the next time the ESP8266 is started. Clicking on the RESET ESP8266 button will 140 | restart it. 141 | 142 |

Configuration in AP mode:

143 | 144 | If the ESP8266 is moved to a WIFI with a different ssid/password, it will not be able to connect using 145 | it's current settings. Upon startup, the ESP attempts to connect to the Wifi that is stored in EEPROM. This 146 | attempts are aborted if unsucessful after 10 seconds. The ESP will then start up in AP mode. This provides 147 | a method of accessing the ESP to modify the Wifi parameters as needed. To access the ESP in AP mode, 148 | connect to the ESP with the ssid "_AP". Then simply open a web browser (from computer, 149 | tablet, or smartphone) and enter: 150 | 151 | http://192.168.4.1:9701/config 152 | 153 | This will open the configuration panel. The AP IP "192.168.4.1" can also be modified through the configuration 154 | panel.. 155 | 156 |

Final note:

157 | 158 | Note that the Serial Interface is set by default to a very slow 1200 baud rate. This is necessary for 159 | reliable operation when intefacing with Arduino using the Arduino Software Serial (Digital pins 10 & 11) 160 | interface. This baud can be used if using a serial hardware bus such as one fount with the Arduino Mega or 161 | if the Arduino interface is not being used. If not used. it is suggested to uncheck the "Arduino Server On" 162 | checkbox. This enables serial output during operation which is inhibited when the serial bus is used 163 | to communicate with an Arduino. 164 | 165 | 166 | 167 | 168 | 169 | 170 | -------------------------------------------------------------------------------- /UtilityFunctions/UtilityFunctions.cpp: -------------------------------------------------------------------------------- 1 | /******************************************************* 2 | This is a library of utility functions 3 | 4 | Designed specifically to work with ESP8266 in the 5 | Arduino IDE platform. 6 | 7 | Written by Dave St. Aubin. 8 | Creative Commons license. 9 | *******************************************************/ 10 | #include "UtilityFunctions.h" 11 | 12 | /******************************************************* 13 | * Replaces the math.h pwr function since we cannot 14 | * successfully link to it with the ESP8266 Arduino IDE 15 | *******************************************************/ 16 | float powr(float x, int y) 17 | { 18 | float temp; 19 | if( y == 0) 20 | return 1; 21 | temp = powr(x, y/2); 22 | if (y%2 == 0) 23 | return temp*temp; 24 | else 25 | { 26 | if(y > 0) 27 | return x*temp*temp; 28 | else 29 | return (temp*temp)/x; 30 | } 31 | } 32 | 33 | // reverses a string 'str' of length 'len' 34 | void reverse(char *str, int len) 35 | { 36 | int i=0, j=len-1, temp; 37 | while (i 5 | sentence=Utility Functions to overcome ESP8266 shortcomings 6 | paragraph=Utility Functions to overcome ESP8266 shortcomings 7 | category=Sensors 8 | url=* 9 | architectures=* 10 | -------------------------------------------------------------------------------- /http_mqtt_server/PAGE_NetworkConfiguration.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | // 4 | // HTML PAGE 5 | // 6 | const char PAGE_NetCfg[] PROGMEM = R"=====( 7 | 8 | 9 | 10 | Configure ESP8266 Wifi 11 | 12 | 13 | 14 |
15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 |
Internet Connectivity
Network Settings
SSID:
Password:
Server Port:
IP: ...
Netmask:...
Gateway:...
AP Mode IP:...
FOTA Password:
FOTA Port:
MQTT Settings
Broker:
Port:
ClientId:
User Name:
Password:
Rx Topic:
Tx Topic:
PW Enable:
Serial Interface
Baud:
Arduino Server On:
47 |
48 |
49 | 50 | 51 | 89 | 90 | 91 | )====="; 92 | 93 | const char PAGE_NetCfg2[] PROGMEM = R"=====( 94 | 95 | 96 | 97 | Configure ESP8266 Wifi 98 | 99 | 100 | 101 |
102 |
103 | 104 | 105 | 106 | 107 | 108 | 109 |
Internet Connectivity
Network Settings
SSID:
Will this fit.?
110 |
111 | 112 | 113 | )====="; 114 | 115 | const char PAGE_WaitAndReload[] PROGMEM = R"=====( 116 | 117 | Please Wait....Configuring and Restarting. 118 | )====="; 119 | 120 | const char PAGE_WaitAndReset[] PROGMEM = R"=====( 121 | 122 | Please Wait....Reseting ESP8266. 123 | )====="; 124 | 125 | 126 | 127 | 128 | -------------------------------------------------------------------------------- /http_mqtt_server/Page_Style.css.h: -------------------------------------------------------------------------------- 1 | 2 | const char PAGE_Style_css[] PROGMEM = R"=====( 3 | body { color: #000000; font-family: avenir, helvetica, arial, sans-serif; letter-spacing: 0.15em;} 4 | hr { background-color: #eee; border: 0 none; color: #eee; height: 1px; } 5 | #mqtt_bk, #mqtt_un, #mqtt_pw, #mqtt_rt, #mqtt_tt, { 6 | width:240px; 7 | } 8 | #headrow { 9 | font-size:28px !important; 10 | } 11 | .btn, .btn:link, .btn:visited { 12 | border-radius: 0.3em; 13 | border-style: solid; 14 | border-width: 1px; 15 | color: #111; 16 | display: inline-block; 17 | font-family: avenir, helvetica, arial, sans-serif; 18 | letter-spacing: 0.15em; 19 | margin-bottom: 0.5em; 20 | padding: 1em 0.75em; 21 | text-decoration: none; 22 | text-transform: uppercase; 23 | -webkit-transition: color 0.4s, background-color 0.4s, border 0.4s; 24 | transition: color 0.4s, background-color 0.4s, border 0.4s; 25 | } 26 | .btn:hover, .btn:focus { 27 | color: #7FDBFF; 28 | border: 1px solid #7FDBFF; 29 | -webkit-transition: background-color 0.3s, color 0.3s, border 0.3s; 30 | transition: background-color 0.3s, color 0.3s, border 0.3s; 31 | } 32 | .btn:active { 33 | color: #0074D9; 34 | border: 1px solid #0074D9; 35 | -webkit-transition: background-color 0.3s, color 0.3s, border 0.3s; 36 | transition: background-color 0.3s, color 0.3s, border 0.3s; 37 | } 38 | .btn--s 39 | { 40 | font-size: 12px; 41 | } 42 | .btn--m { 43 | font-size: 14px; 44 | } 45 | .btn--l { 46 | font-size: 20px; border-radius: 0.25em !important; 47 | } 48 | .btn--full, .btn--full:link { 49 | border-radius: 0.25em; 50 | display: block; 51 | margin-left: auto; 52 | margin-right: auto; 53 | text-align: center; 54 | width: 100%; 55 | } 56 | .btn--blue:link, .btn--blue:visited { 57 | color: #fff; 58 | background-color: #0074D9; 59 | } 60 | .btn--blue:hover, .btn--blue:focus { 61 | color: #fff !important; 62 | background-color: #0063aa; 63 | border-color: #0063aa; 64 | } 65 | .btn--blue:active { 66 | color: #fff; 67 | background-color: #001F3F; border-color: #001F3F; 68 | } 69 | @media screen and (min-width: 32em) { 70 | .btn--full { 71 | max-width: 16em !important; } 72 | } 73 | )====="; 74 | 75 | const char PAGE_Style2_css[] PROGMEM = R"=====( 76 | 77 | .btn:hover, .btn:focus { 78 | color: #7FDBFF; 79 | border: 1px solid #7FDBFF; 80 | -webkit-transition: background-color 0.3s, color 0.3s, border 0.3s; 81 | transition: background-color 0.3s, color 0.3s, border 0.3s; 82 | } 83 | .btn:active { 84 | color: #0074D9; 85 | border: 1px solid #0074D9; 86 | -webkit-transition: background-color 0.3s, color 0.3s, border 0.3s; 87 | transition: background-color 0.3s, color 0.3s, border 0.3s; 88 | } 89 | .btn--s 90 | { 91 | font-size: 12px; 92 | } 93 | .btn--m { 94 | font-size: 14px; 95 | } 96 | .btn--l { 97 | font-size: 20px; border-radius: 0.25em !important; 98 | } 99 | .btn--full, .btn--full:link { 100 | border-radius: 0.25em; 101 | display: block; 102 | margin-left: auto; 103 | margin-right: auto; 104 | text-align: center; 105 | width: 100%; 106 | } 107 | .btn--blue:link, .btn--blue:visited { 108 | color: #fff; 109 | background-color: #0074D9; 110 | } 111 | .btn--blue:hover, .btn--blue:focus { 112 | color: #fff !important; 113 | background-color: #0063aa; 114 | border-color: #0063aa; 115 | } 116 | .btn--blue:active { 117 | color: #fff; 118 | background-color: #001F3F; border-color: #001F3F; 119 | } 120 | @media screen and (min-width: 32em) { 121 | .btn--full { 122 | max-width: 16em !important; } 123 | } 124 | )====="; 125 | 126 | -------------------------------------------------------------------------------- /http_mqtt_server/sketch.h: -------------------------------------------------------------------------------- 1 | #ifndef SKETCH_H 2 | #define SKETCH_H 1 3 | 4 | 5 | //Server actions 6 | #define SET_LED_OFF 0 7 | #define SET_LED_ON 1 8 | #define BLINK_LED 2 9 | #define Get_SENSORS 3 10 | #define ARDUINO_REQUEST 4 11 | #define INVALID_REQUEST 99 12 | 13 | //Server Type 14 | #define SVR_MQTT 0 15 | #define SVR_HTTP_LIB 1 16 | #define SVR_HTTP_SDK 2 17 | #define SVR_COAP 3 18 | #define SVR_NONE 10 19 | 20 | //Reply Type 21 | #define REPLY_JSON 0 22 | #define REPLY_TEXT 1 23 | 24 | //Set this to desired server type (see above 4 types) 25 | #define SVR_TYPE SVR_HTTP_SDK 26 | #define MQTT_SVR_ENABLE 1 27 | #define COAP_SVR_ENABLE 0 28 | 29 | //JSON string type 30 | #define ONEJSON 0 31 | #define FIRSTJSON 1 32 | #define NEXTJSON 2 33 | #define LASTJSON 3 34 | 35 | //GPIO pin assignments 36 | #define AMUXSEL0 14 // AMUX Selector 0 37 | #define AMUXSEL1 12 // AMUX Selector 1 38 | #define AMUXSEL2 13 // AMUX Selector 2 39 | #define LED_IND 16 // LED used for initial code testing (not included in final hardware design) 40 | 41 | #define URLSize 32 42 | #define DATASize 32 43 | 44 | #define EEPROM_INIT 0 45 | #define EEPROM_WIFISSID 0x10 46 | #define EEPROM_WIFIPASS 0x30 47 | #define EEPROM_WIFI_IP0 0x40 48 | #define EEPROM_WIFI_IP1 0x41 49 | #define EEPROM_WIFI_IP2 0x42 50 | #define EEPROM_WIFI_IP3 0x43 51 | #define EEPROM_WIFI_NM0 0x44 52 | #define EEPROM_WIFI_NM1 0x45 53 | #define EEPROM_WIFI_NM2 0x46 54 | #define EEPROM_WIFI_NM3 0x47 55 | #define EEPROM_WIFI_GW0 0x48 56 | #define EEPROM_WIFI_GW1 0x49 57 | #define EEPROM_WIFI_GW2 0x4A 58 | #define EEPROM_WIFI_GW3 0x4B 59 | #define EEPROM_WIFI_AP0 0x4C 60 | #define EEPROM_WIFI_AP1 0x4D 61 | #define EEPROM_WIFI_AP2 0x4E 62 | #define EEPROM_WIFI_AP3 0x4F 63 | #define EEPROM_SVR_PORT 0x50 64 | #define EEPROM_MQTT_BK 0x60 65 | #define EEPROM_MQTT_UN 0x80 66 | #define EEPROM_MQTT_PW 0xA0 67 | #define EEPROM_MQTT_RT 0xC0 68 | #define EEPROM_MQTT_TT 0xE0 69 | #define EEPROM_SER_BAUD 0x100 70 | #define EEPROM_SER_SERV 0x108 71 | #define EEPROM_MQTTPWEN 0x110 72 | #define EEPROM_MQTT_PT 0x118 73 | #define EEPROM_FOTA_PT 0x11A 74 | #define EEPROM_FOTA_PW 0x120 75 | #define EEPROM_MQTT_CI 0x140 76 | 77 | #define EEPROM_CHR 0 78 | #define EEPROM_INT 1 79 | #define EEPROM_INT16 2 80 | #define EEPROM_INT24 3 81 | #define ADD_CSS 4 82 | 83 | 84 | typedef struct RQST_Param { 85 | int request; 86 | int requestval; 87 | } RQST_Param; 88 | 89 | typedef enum ProtocolType { 90 | GET = 0, 91 | POST, 92 | GET_FAVICON 93 | } ProtocolType; 94 | 95 | typedef struct URL_Param { 96 | enum ProtocolType Type; 97 | char pParam[URLSize][URLSize]; 98 | char pParVal[URLSize][URLSize]; 99 | int nPar; 100 | } URL_Param; 101 | 102 | #endif 103 | -------------------------------------------------------------------------------- /http_mqtt_server_SSL/PAGE_NetworkConfiguration.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | // 4 | // HTML PAGE 5 | // 6 | const char PAGE_NetCfg[] PROGMEM = R"=====( 7 | 8 | 9 | 10 | Configure ESP8266 Wifi 11 | 12 | 13 | 14 |
15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 |
Internet Connectivity
Network Settings
SSID:
Password:
Server Port:
IP: ...
Netmask:...
Gateway:...
AP Mode IP:...
FOTA Password:
FOTA Port:
MQTT Settings
Broker:
Port:
ClientId:
User Name:
Password:
Rx Topic:
Tx Topic:
PW Enable:
TLS Enable:
MQTT Enable:
Serial Interface
Baud:
Arduino Server On:
49 |
50 |
51 | 52 | 92 | 93 | 94 | )====="; 95 | 96 | const char PAGE_NetCfg2[] PROGMEM = R"=====( 97 | 98 | 99 | 100 | Configure ESP8266 Wifi 101 | 102 | 103 | 104 |
105 |
106 | 107 | 108 | 109 | 110 | 111 | 112 |
Internet Connectivity
Network Settings
SSID:
Will this fit.?
113 |
114 | 115 | 116 | )====="; 117 | 118 | const char PAGE_WaitAndReload[] PROGMEM = R"=====( 119 | 120 | Please Wait....Configuring and Restarting. 121 | )====="; 122 | 123 | const char PAGE_WaitAndReset[] PROGMEM = R"=====( 124 | 125 | Please Wait....Reseting ESP8266. 126 | )====="; 127 | 128 | 129 | 130 | 131 | -------------------------------------------------------------------------------- /http_mqtt_server_SSL/Page_Style.css.h: -------------------------------------------------------------------------------- 1 | 2 | const char PAGE_Style_css[] PROGMEM = R"=====( 3 | body { color: #000000; font-family: avenir, helvetica, arial, sans-serif; letter-spacing: 0.15em;} 4 | hr { background-color: #eee; border: 0 none; color: #eee; height: 1px; } 5 | #mqtt_bk, #mqtt_un, #mqtt_pw, #mqtt_rt, #mqtt_tt, { 6 | width:240px; 7 | } 8 | #headrow { 9 | font-size:28px !important; 10 | } 11 | .btn, .btn:link, .btn:visited { 12 | border-radius: 0.3em; 13 | border-style: solid; 14 | border-width: 1px; 15 | color: #111; 16 | display: inline-block; 17 | font-family: avenir, helvetica, arial, sans-serif; 18 | letter-spacing: 0.15em; 19 | margin-bottom: 0.5em; 20 | padding: 1em 0.75em; 21 | text-decoration: none; 22 | text-transform: uppercase; 23 | -webkit-transition: color 0.4s, background-color 0.4s, border 0.4s; 24 | transition: color 0.4s, background-color 0.4s, border 0.4s; 25 | } 26 | .btn:hover, .btn:focus { 27 | color: #7FDBFF; 28 | border: 1px solid #7FDBFF; 29 | -webkit-transition: background-color 0.3s, color 0.3s, border 0.3s; 30 | transition: background-color 0.3s, color 0.3s, border 0.3s; 31 | } 32 | .btn:active { 33 | color: #0074D9; 34 | border: 1px solid #0074D9; 35 | -webkit-transition: background-color 0.3s, color 0.3s, border 0.3s; 36 | transition: background-color 0.3s, color 0.3s, border 0.3s; 37 | } 38 | .btn--s 39 | { 40 | font-size: 12px; 41 | } 42 | .btn--m { 43 | font-size: 14px; 44 | } 45 | .btn--l { 46 | font-size: 20px; border-radius: 0.25em !important; 47 | } 48 | .btn--full, .btn--full:link { 49 | border-radius: 0.25em; 50 | display: block; 51 | margin-left: auto; 52 | margin-right: auto; 53 | text-align: center; 54 | width: 100%; 55 | } 56 | .btn--blue:link, .btn--blue:visited { 57 | color: #fff; 58 | background-color: #0074D9; 59 | } 60 | .btn--blue:hover, .btn--blue:focus { 61 | color: #fff !important; 62 | background-color: #0063aa; 63 | border-color: #0063aa; 64 | } 65 | .btn--blue:active { 66 | color: #fff; 67 | background-color: #001F3F; border-color: #001F3F; 68 | } 69 | @media screen and (min-width: 32em) { 70 | .btn--full { 71 | max-width: 16em !important; } 72 | } 73 | )====="; 74 | 75 | const char PAGE_Style2_css[] PROGMEM = R"=====( 76 | 77 | .btn:hover, .btn:focus { 78 | color: #7FDBFF; 79 | border: 1px solid #7FDBFF; 80 | -webkit-transition: background-color 0.3s, color 0.3s, border 0.3s; 81 | transition: background-color 0.3s, color 0.3s, border 0.3s; 82 | } 83 | .btn:active { 84 | color: #0074D9; 85 | border: 1px solid #0074D9; 86 | -webkit-transition: background-color 0.3s, color 0.3s, border 0.3s; 87 | transition: background-color 0.3s, color 0.3s, border 0.3s; 88 | } 89 | .btn--s 90 | { 91 | font-size: 12px; 92 | } 93 | .btn--m { 94 | font-size: 14px; 95 | } 96 | .btn--l { 97 | font-size: 20px; border-radius: 0.25em !important; 98 | } 99 | .btn--full, .btn--full:link { 100 | border-radius: 0.25em; 101 | display: block; 102 | margin-left: auto; 103 | margin-right: auto; 104 | text-align: center; 105 | width: 100%; 106 | } 107 | .btn--blue:link, .btn--blue:visited { 108 | color: #fff; 109 | background-color: #0074D9; 110 | } 111 | .btn--blue:hover, .btn--blue:focus { 112 | color: #fff !important; 113 | background-color: #0063aa; 114 | border-color: #0063aa; 115 | } 116 | .btn--blue:active { 117 | color: #fff; 118 | background-color: #001F3F; border-color: #001F3F; 119 | } 120 | @media screen and (min-width: 32em) { 121 | .btn--full { 122 | max-width: 16em !important; } 123 | } 124 | )====="; 125 | 126 | -------------------------------------------------------------------------------- /http_mqtt_server_SSL/sketch.h: -------------------------------------------------------------------------------- 1 | #ifndef SKETCH_H 2 | #define SKETCH_H 1 3 | 4 | 5 | //Server actions 6 | #define SET_LED_OFF 0 7 | #define SET_LED_ON 1 8 | #define BLINK_LED 2 9 | #define Get_SENSORS 3 10 | #define ARDUINO_REQUEST 4 11 | #define SET_HTTP_ON 5 12 | #define SET_MQTTSSL_ON 6 13 | #define INVALID_REQUEST 99 14 | 15 | //Server Type 16 | #define SVR_MQTT 0 17 | #define SVR_HTTP_LIB 1 18 | #define SVR_HTTP_SDK 2 19 | #define SVR_COAP 3 20 | #define SVR_NONE 10 21 | 22 | //Reply Type 23 | #define REPLY_JSON 0 24 | #define REPLY_TEXT 1 25 | 26 | //Set this to desired server type (see above 4 types) 27 | #define SVR_TYPE SVR_HTTP_SDK 28 | #define MQTT_SVR_ENABLE 1 29 | #define COAP_SVR_ENABLE 0 30 | 31 | //JSON string type 32 | #define ONEJSON 0 33 | #define FIRSTJSON 1 34 | #define NEXTJSON 2 35 | #define LASTJSON 3 36 | 37 | //GPIO pin assignments 38 | #define AMUXSEL0 14 // AMUX Selector 0 39 | #define AMUXSEL1 12 // AMUX Selector 1 40 | #define AMUXSEL2 13 // AMUX Selector 2 41 | #define LED_IND 16 // LED used for initial code testing (not included in final hardware design) 42 | 43 | #define URLSize 32 44 | #define DATASize 32 45 | 46 | #define EEPROM_INIT 0 47 | #define EEPROM_WIFISSID 0x10 48 | #define EEPROM_WIFIPASS 0x30 49 | #define EEPROM_WIFI_IP0 0x40 50 | #define EEPROM_WIFI_IP1 0x41 51 | #define EEPROM_WIFI_IP2 0x42 52 | #define EEPROM_WIFI_IP3 0x43 53 | #define EEPROM_WIFI_NM0 0x44 54 | #define EEPROM_WIFI_NM1 0x45 55 | #define EEPROM_WIFI_NM2 0x46 56 | #define EEPROM_WIFI_NM3 0x47 57 | #define EEPROM_WIFI_GW0 0x48 58 | #define EEPROM_WIFI_GW1 0x49 59 | #define EEPROM_WIFI_GW2 0x4A 60 | #define EEPROM_WIFI_GW3 0x4B 61 | #define EEPROM_WIFI_AP0 0x4C 62 | #define EEPROM_WIFI_AP1 0x4D 63 | #define EEPROM_WIFI_AP2 0x4E 64 | #define EEPROM_WIFI_AP3 0x4F 65 | #define EEPROM_SVR_PORT 0x50 66 | #define EEPROM_MQTT_BK 0x60 67 | #define EEPROM_MQTT_UN 0x80 68 | #define EEPROM_MQTT_PW 0xA0 69 | #define EEPROM_MQTT_RT 0xC0 70 | #define EEPROM_MQTT_TT 0xE0 71 | #define EEPROM_SER_BAUD 0x100 72 | #define EEPROM_SER_SERV 0x108 73 | #define EEPROM_MQTTPWEN 0x110 74 | #define EEPROM_MQTTSSLEN 0x160 75 | #define EEPROM_MQTTCLEN 0x170 76 | #define EEPROM_MQTT_PT 0x118 77 | #define EEPROM_FOTA_PT 0x11A 78 | #define EEPROM_FOTA_PW 0x120 79 | #define EEPROM_MQTT_CI 0x140 80 | 81 | #define EEPROM_CHR 0 82 | #define EEPROM_INT 1 83 | #define EEPROM_INT16 2 84 | #define EEPROM_INT24 3 85 | #define ADD_CSS 4 86 | 87 | 88 | typedef struct RQST_Param { 89 | int request; 90 | int requestval; 91 | } RQST_Param; 92 | 93 | typedef enum ProtocolType { 94 | GET = 0, 95 | POST, 96 | GET_FAVICON 97 | } ProtocolType; 98 | 99 | typedef struct URL_Param { 100 | enum ProtocolType Type; 101 | char pParam[URLSize][URLSize]; 102 | char pParVal[URLSize][URLSize]; 103 | int nPar; 104 | } URL_Param; 105 | 106 | #endif 107 | -------------------------------------------------------------------------------- /webserver/lwipopts.h: -------------------------------------------------------------------------------- 1 | #ifndef __LWIPOPTS_H__ 2 | #define __LWIPOPTS_H__ 3 | 4 | #include "mem_manager.h" 5 | #include "eagle_soc.h" 6 | 7 | // Don't change: 8 | #define NO_SYS 1 9 | #define NO_SYS_NO_TIMERS 0 10 | #define LWIP_NETIF_TX_SINGLE_PBUF 1 11 | #define LWIP_ESP 1 12 | #define PBUF_RSV_FOR_WLAN 1 13 | #define ICACHE_FLASH 1 14 | #define EBUF_LWIP 1 15 | 16 | // Leave unchanged unless you really know what you're doing: 17 | #define MEM_ALIGNMENT 4 18 | #define TCP_MSS 1460 19 | #define TCP_SND_BUF (2*TCP_MSS) 20 | #define MEMP_MEM_MALLOC 1 21 | #define MEM_LIBC_MALLOC 1 22 | 23 | #define MEMP_NUM_TCP_PCB (*((volatile uint32*)0x600011FC)) 24 | #define LWIP_RAND() rand() 25 | 26 | #if MEM_LIBC_MALLOC 27 | #define mem_free vPortFree 28 | #define mem_malloc pvPortMalloc 29 | #define mem_calloc pvPortCalloc 30 | #endif 31 | 32 | #define MEMCPY(dst,src,len) os_memcpy(dst,src,len) 33 | #define SMEMCPY(dst,src,len) os_memcpy(dst,src,len) 34 | 35 | static inline uint32_t sys_now(void) 36 | { 37 | return NOW()/(TIMER_CLK_FREQ/1000); 38 | } 39 | 40 | // For espconn: 41 | //#define os_malloc(s) pvPortMalloc((s)) 42 | //#define os_realloc(p, s) pvPortRealloc((p), (s)) 43 | //#define os_zalloc(s) pvPortZalloc((s)) 44 | //#define os_free(p) vPortFree((p)) 45 | 46 | // Required: 47 | #define LWIP_DHCP 1 48 | #define LWIP_DNS 1 49 | 50 | // Optional: 51 | #define LWIP_IGMP 1 52 | #define LWIP_NETIF_LOOPBACK 0 53 | #define LWIP_HAVE_LOOPIF 0 54 | 55 | // Tweakable: 56 | #define ESP_TIMEWAIT_THRESHOLD 10000 57 | 58 | #define TCP_TMR_INTERVAL 125 59 | #define TCP_KEEPIDLE_DEFAULT 3000 60 | #define TCP_KEEPINTVL_DEFAULT 1000 61 | #define TCP_KEEPCNT_DEFAULT 3 62 | 63 | #define LWIP_NETCONN 0 64 | #define LWIP_SOCKET 0 65 | #define MEMP_NUM_SYS_TIMEOUT 8 66 | 67 | #define TCP_LOCAL_PORT_RANGE_START 0x1000 68 | #define TCP_LOCAL_PORT_RANGE_END 0x7fff 69 | #define UDP_LOCAL_PORT_RANGE_START 0x1000 70 | #define UDP_LOCAL_PORT_RANGE_END 0x7fff 71 | 72 | #define ARP_QUEUEING 1 73 | #define ETHARP_TRUST_IP_MAC 1 74 | #define IP_FRAG 0 75 | #define IP_REASSEMBLY 0 76 | #define IP_FRAG_USES_STATIC_BUF 1 77 | #define TCP_QUEUE_OOSEQ 0 78 | #define LWIP_TCP_KEEPALIVE 1 79 | #define LWIP_STATS 0 80 | 81 | #ifdef LWIP_OUR_IF 82 | #define LWIP_NETIF_HOSTNAME 1 // our eagle_lwip_if.o required 83 | #define LWIP_NETIF_HOSTNAME_PREFIX "esp8266-" 84 | #endif 85 | 86 | // #define LWIP_DEBUG 87 | // #define IP_DEBUG LWIP_DBG_ON 88 | 89 | #endif /* __LWIP_OPT_H__ */ 90 | -------------------------------------------------------------------------------- /webserver/mem_manager.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/internetofhomethings/Configurable-Web-Server/38879014a7db6cd5804a302e143d954b3d22765b/webserver/mem_manager.h -------------------------------------------------------------------------------- /webserver/user_webserver.h: -------------------------------------------------------------------------------- 1 | #ifndef __USER_WEBSERVER_H__ 2 | #define __USER_WEBSERVER_H__ 3 | 4 | #define SERVER_PORT 9703 5 | #define SERVER_SSL_PORT 443 6 | 7 | #define URLSize 10 8 | #define DATASize 10 9 | 10 | typedef enum Result_Resp { 11 | RespFail = 0, 12 | RespSuc, 13 | } Result_Resp; 14 | 15 | typedef enum ProtocolType { 16 | GET = 0, 17 | POST, 18 | GET_FAVICON 19 | } ProtocolType; 20 | 21 | typedef enum _ParmType { 22 | SWITCH_STATUS = 0, 23 | INFOMATION, 24 | WIFI, 25 | SCAN, 26 | REBOOT, 27 | DEEP_SLEEP, 28 | LIGHT_STATUS, 29 | CONNECT_STATUS, 30 | USER_BIN, 31 | GET_SENSORS 32 | } ParmType; 33 | 34 | typedef struct DATA_Sensors { 35 | char tDht11[DATASize]; 36 | char hDht11[DATASize]; 37 | char tBmp085[DATASize]; 38 | char pBmp085[DATASize]; 39 | char aBmp085[DATASize]; 40 | char t1Ds18b20[DATASize]; 41 | char t2Ds18b20[DATASize]; 42 | } DATA_Sensors; 43 | 44 | typedef struct DATA_System { 45 | char freeheap[DATASize]; 46 | char systime[DATASize]; 47 | char loopcnt[DATASize]; 48 | char wifimode[DATASize]; 49 | char wifistatus[DATASize]; 50 | char wifireconnects[DATASize]; 51 | } DATA_System; 52 | 53 | typedef struct URL_Frame { 54 | enum ProtocolType Type; 55 | char pSelect[URLSize]; 56 | char pCommand[URLSize]; 57 | char pFilename[URLSize]; 58 | } URL_Frame; 59 | 60 | typedef struct URL_Param { 61 | enum ProtocolType Type; 62 | char pParam[URLSize][URLSize]; 63 | char pParVal[URLSize][URLSize]; 64 | int nPar; 65 | } URL_Param; 66 | 67 | typedef struct _rst_parm { 68 | ParmType parmtype; 69 | struct espconn *pespconn; 70 | } rst_parm; 71 | 72 | void user_webserver_init(uint32 port); 73 | 74 | #endif 75 | --------------------------------------------------------------------------------