├── .gitattributes ├── .gitignore ├── README.md ├── SSDPDevice.cpp ├── SSDPDevice.h ├── SSDPinNetwork.PNG ├── esp32SSDP.ino ├── update_server.h ├── update_server.ino ├── wifi_ss.h └── wifi_ss.ino /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.bin 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # esp32SSDP 2 | SSDP for ESP32, including http updater without JQuery 3 | based on https://github.com/esp8266/Arduino/issues/2283 4 | https://github.com/esp8266/Arduino/files/980894/SSDPDevice.zip 5 | by Pawel Dino 6 |

7 | Shows the ESP32 in Windows Network tab under Home Automation. 8 |

9 | 10 |

11 | The example needs a ssid and password defined for the WiFi credentials see 12 | wifi_ss.h 13 |

14 | Included httpupdater code that is independent of JQuery, and lacks 15 | the overload of braces that confuse me. 16 | 17 | -------------------------------------------------------------------------------- /SSDPDevice.cpp: -------------------------------------------------------------------------------- 1 | // based on https://github.com/esp8266/Arduino/issues/2283 2 | // https://github.com/esp8266/Arduino/files/980894/SSDPDevice.zip 3 | // by Pawel Dino 4 | 5 | 6 | #include "SSDPDevice.h" 7 | #include "lwip/igmp.h" 8 | 9 | SSDPDeviceClass::SSDPDeviceClass() : 10 | m_server(0), 11 | m_port(80), 12 | m_ttl(SSDP_MULTICAST_TTL) 13 | { 14 | m_uuid[0] = '\0'; 15 | m_modelNumber[0] = '\0'; 16 | sprintf(m_deviceType, "urn:schemas-upnp-org:device:Basic:1"); 17 | m_friendlyName[0] = '\0'; 18 | m_presentationURL[0] = '\0'; 19 | m_serialNumber[0] = '\0'; 20 | m_modelName[0] = '\0'; 21 | m_modelURL[0] = '\0'; 22 | m_manufacturer[0] = '\0'; 23 | m_manufacturerURL[0] = '\0'; 24 | sprintf(m_schemaURL, "ssdp/schema.xml"); 25 | 26 | #ifdef ESP8266 27 | uint32_t chipId = ESP.getChipId(); 28 | #endif 29 | #ifdef ESP32 30 | uint32_t chipId = ESP.getEfuseMac(); 31 | #endif 32 | 33 | sprintf(m_uuid, "38323636-4558-4dda-9188-cda0e6%02x%02x%02x", 34 | (uint16_t)((chipId >> 16) & 0xff), 35 | (uint16_t)((chipId >> 8) & 0xff), 36 | (uint16_t)chipId & 0xff); 37 | 38 | for (int i = 0; i < SSDP_QUEUE_SIZE; i++) { 39 | m_queue[i].time = 0; 40 | } 41 | } 42 | 43 | void SSDPDeviceClass::update() { 44 | postNotifyUpdate(); 45 | } 46 | 47 | bool SSDPDeviceClass::readLine(String &value) { 48 | char buffer[65]; 49 | int bufferPos = 0; 50 | 51 | while (1) { 52 | int c = m_server->read(); 53 | 54 | if (c < 0) { 55 | buffer[bufferPos] = '\0'; 56 | 57 | break; 58 | } 59 | if (c == '\r' && m_server->peek() == '\n') { 60 | m_server->read(); 61 | 62 | buffer[bufferPos] = '\0'; 63 | 64 | break; 65 | } 66 | if (bufferPos < 64) { 67 | buffer[bufferPos++] = c; 68 | } 69 | } 70 | 71 | value = String(buffer); 72 | 73 | return bufferPos > 0; 74 | } 75 | 76 | bool SSDPDeviceClass::readKeyValue(String &key, String &value) { 77 | char buffer[65]; 78 | int bufferPos = 0; 79 | 80 | while (1) { 81 | int c = m_server->read(); 82 | 83 | if (c < 0) { 84 | if (bufferPos == 0) return false; 85 | 86 | buffer[bufferPos] = '\0'; 87 | 88 | break; 89 | } 90 | if (c == ':') { 91 | buffer[bufferPos] = '\0'; 92 | 93 | while (m_server->peek() == ' ') m_server->read(); 94 | 95 | break; 96 | } 97 | else if (c == '\r' && m_server->peek() == '\n') { 98 | m_server->read(); 99 | 100 | if (bufferPos == 0) return false; 101 | 102 | buffer[bufferPos] = '\0'; 103 | 104 | key = String(); 105 | value = String(buffer); 106 | 107 | return true; 108 | } 109 | if (bufferPos < 64) { 110 | buffer[bufferPos++] = c; 111 | } 112 | } 113 | 114 | key = String(buffer); 115 | 116 | readLine(value); 117 | 118 | return true; 119 | } 120 | 121 | void SSDPDeviceClass::postNotifyALive() { 122 | unsigned long time = millis(); 123 | 124 | post(NOTIFY_ALIVE_INIT, ROOT_FOR_ALL, SSDP_MULTICAST_ADDR, SSDP_PORT, time + 10); 125 | post(NOTIFY_ALIVE_INIT, ROOT_BY_UUID, SSDP_MULTICAST_ADDR, SSDP_PORT, time + 55); 126 | post(NOTIFY_ALIVE_INIT, ROOT_BY_TYPE, SSDP_MULTICAST_ADDR, SSDP_PORT, time + 80); 127 | 128 | post(NOTIFY_ALIVE_INIT, ROOT_FOR_ALL, SSDP_MULTICAST_ADDR, SSDP_PORT, time + 210); 129 | post(NOTIFY_ALIVE_INIT, ROOT_BY_UUID, SSDP_MULTICAST_ADDR, SSDP_PORT, time + 255); 130 | post(NOTIFY_ALIVE_INIT, ROOT_BY_TYPE, SSDP_MULTICAST_ADDR, SSDP_PORT, time + 280); 131 | 132 | post(NOTIFY_ALIVE, ROOT_FOR_ALL, SSDP_MULTICAST_ADDR, SSDP_PORT, time + 610); 133 | post(NOTIFY_ALIVE, ROOT_BY_UUID, SSDP_MULTICAST_ADDR, SSDP_PORT, time + 655); 134 | post(NOTIFY_ALIVE, ROOT_BY_TYPE, SSDP_MULTICAST_ADDR, SSDP_PORT, time + 680); 135 | } 136 | 137 | void SSDPDeviceClass::postNotifyUpdate() { 138 | unsigned long time = millis(); 139 | 140 | post(NOTIFY_UPDATE, ROOT_FOR_ALL, SSDP_MULTICAST_ADDR, SSDP_PORT, time + 10); 141 | post(NOTIFY_UPDATE, ROOT_BY_UUID, SSDP_MULTICAST_ADDR, SSDP_PORT, time + 55); 142 | post(NOTIFY_UPDATE, ROOT_BY_TYPE, SSDP_MULTICAST_ADDR, SSDP_PORT, time + 80); 143 | } 144 | 145 | void SSDPDeviceClass::postResponse(long mx) { 146 | unsigned long time = millis(); 147 | unsigned long delay = random(0, mx) * 900L; // 1000 ms - 100 ms 148 | 149 | IPAddress address = m_server->remoteIP(); 150 | uint16_t port = m_server->remotePort(); 151 | 152 | post(RESPONSE, ROOT_FOR_ALL, address, port, time + delay / 3); 153 | post(RESPONSE, ROOT_BY_UUID, address, port, time + delay / 3 * 2); 154 | post(RESPONSE, ROOT_BY_TYPE, address, port, time + delay); 155 | } 156 | 157 | void SSDPDeviceClass::postResponse(ssdp_udn_t udn, long mx) { 158 | post(RESPONSE, udn, m_server->remoteIP(), m_server->remotePort(), millis() + random(0, mx) * 900L); // 1000 ms - 100 ms 159 | } 160 | 161 | void SSDPDeviceClass::post(ssdp_message_t type, ssdp_udn_t udn, IPAddress address, uint16_t port, unsigned long time) { 162 | for (int i = 0; i < SSDP_QUEUE_SIZE; i++) { 163 | if (m_queue[i].time == 0) { 164 | m_queue[i].type = type; 165 | m_queue[i].udn = udn; 166 | m_queue[i].address = address; 167 | m_queue[i].port = port; 168 | m_queue[i].time = time; 169 | 170 | break; 171 | } 172 | } 173 | } 174 | 175 | void SSDPDeviceClass::send(ssdp_send_parameters_t *parameters) { 176 | uint8_t buffer[1460]; 177 | unsigned int ip = WiFi.localIP(); 178 | 179 | const char *typeTemplate; 180 | const char *uri, *usn1, *usn2, *usn3; 181 | 182 | switch (parameters->type) { 183 | case NOTIFY_ALIVE_INIT: 184 | case NOTIFY_ALIVE: 185 | typeTemplate = SSDP_NOTIFY_ALIVE_TEMPLATE; 186 | break; 187 | case NOTIFY_UPDATE: 188 | typeTemplate = SSDP_NOTIFY_UPDATE_TEMPLATE; 189 | break; 190 | default: // RESPONSE 191 | typeTemplate = SSDP_RESPONSE_TEMPLATE; 192 | break; 193 | } 194 | 195 | String uuid = "uuid:" + String(m_uuid); 196 | 197 | switch (parameters->udn) { 198 | case ROOT_FOR_ALL: 199 | uri = "upnp:rootdevice"; 200 | usn1 = uuid.c_str(); 201 | usn2 = "::"; 202 | usn3 = "upnp:rootdevice"; 203 | break; 204 | case ROOT_BY_UUID: 205 | uri = uuid.c_str(); 206 | usn1 = uuid.c_str(); 207 | usn2 = ""; 208 | usn3 = ""; 209 | break; 210 | case ROOT_BY_TYPE: 211 | uri = m_deviceType; 212 | usn1 = uuid.c_str(); 213 | usn2 = "::"; 214 | usn3 = m_deviceType; 215 | break; 216 | } 217 | 218 | int len = snprintf_P((char *)buffer, sizeof(buffer), 219 | SSDP_PACKET_TEMPLATE, typeTemplate, 220 | SSDP_INTERVAL, m_modelName, m_modelNumber, usn1, usn2, usn3, parameters->type == RESPONSE ? "ST" : "NT", uri, 221 | LIP2STR(&ip), m_port, m_schemaURL 222 | ); 223 | 224 | if (parameters->address == (uint32_t) SSDP_MULTICAST_ADDR) { 225 | #ifdef ESP8266 226 | m_server->beginPacketMulticast(parameters->address, parameters->port, m_ttl); 227 | #endif 228 | #ifdef ESP32 229 | m_server->beginMulticast(parameters->address, parameters->port); 230 | m_server->beginMulticastPacket(); 231 | #endif 232 | } else { 233 | m_server->beginPacket(parameters->address, parameters->port); 234 | } 235 | 236 | m_server->write(buffer, len); 237 | m_server->endPacket(); 238 | 239 | parameters->time = parameters->type == NOTIFY_ALIVE ? parameters->time + SSDP_INTERVAL * 900L : 0; // 1000 ms - 100 ms 240 | } 241 | 242 | void SSDPDeviceClass::schema(WiFiClient client) { 243 | uint32_t ip = WiFi.localIP(); 244 | client.printf(SSDP_SCHEMA_TEMPLATE, 245 | LIP2STR(&ip), m_port, m_schemaURL, 246 | m_deviceType, 247 | m_friendlyName, 248 | m_presentationURL, 249 | m_serialNumber, 250 | m_modelName, 251 | m_modelNumber, 252 | m_modelURL, 253 | m_manufacturer, 254 | m_manufacturerURL, 255 | m_uuid 256 | ); 257 | } 258 | 259 | void SSDPDeviceClass::handleClient() { 260 | IPAddress current = WiFi.localIP(); 261 | 262 | if (m_last != current) { 263 | m_last = current; 264 | 265 | for (int i = 0; i < SSDP_QUEUE_SIZE; i++) { 266 | m_queue[i].time = 0; 267 | } 268 | 269 | if (current != INADDR_NONE) { 270 | if (!m_server) m_server = new WiFiUDP(); 271 | 272 | #ifdef ESP8266 273 | m_server->beginMulticast(current, SSDP_MULTICAST_ADDR, SSDP_PORT); 274 | #endif 275 | #ifdef ESP32 276 | m_server->beginMulticast(SSDP_MULTICAST_ADDR, SSDP_PORT); 277 | m_server->beginMulticastPacket(); 278 | #endif 279 | postNotifyALive(); 280 | } 281 | else if (m_server) { 282 | m_server->stop(); 283 | } 284 | } 285 | 286 | if (m_server && m_server->parsePacket()) { 287 | String value; 288 | 289 | if (readLine(value) && value.equalsIgnoreCase("M-SEARCH * HTTP/1.1")) { 290 | String key, st; 291 | bool host = false, man = false; 292 | long mx = 0; 293 | 294 | while (readKeyValue(key, value)) { 295 | if (key.equalsIgnoreCase("HOST") && value.equals("239.255.255.250:1900")) { 296 | host = true; 297 | } 298 | else if (key.equalsIgnoreCase("MAN") && value.equals("\"ssdp:discover\"")) { 299 | man = true; 300 | } 301 | else if (key.equalsIgnoreCase("ST")) { 302 | st = value; 303 | } 304 | else if (key.equalsIgnoreCase("MX")) { 305 | mx = value.toInt(); 306 | } 307 | } 308 | 309 | if (host && man && mx > 0) { 310 | if (st.equals("ssdp:all")) { 311 | postResponse(mx); 312 | } 313 | else if (st.equals("upnp:rootdevice")) { 314 | postResponse(ROOT_FOR_ALL, mx); 315 | } 316 | else if (st.equals("uuid:" + String(m_uuid))) { 317 | postResponse(ROOT_BY_UUID, mx); 318 | } 319 | else if (st.equals(m_deviceType)) { 320 | postResponse(ROOT_BY_TYPE, mx); 321 | } 322 | } 323 | } 324 | 325 | m_server->flush(); 326 | } 327 | else { 328 | unsigned long time = millis(); 329 | 330 | for (int i = 0; i < SSDP_QUEUE_SIZE; i++) { 331 | if (m_queue[i].time > 0 && m_queue[i].time < time) { 332 | send(&m_queue[i]); 333 | } 334 | } 335 | } 336 | } 337 | 338 | void SSDPDeviceClass::setSchemaURL(const char *url) { 339 | strlcpy(m_schemaURL, url, sizeof(m_schemaURL)); 340 | } 341 | 342 | void SSDPDeviceClass::setHTTPPort(uint16_t port) { 343 | m_port = port; 344 | } 345 | 346 | void SSDPDeviceClass::setDeviceType(const char *deviceType) { 347 | strlcpy(m_deviceType, deviceType, sizeof(m_deviceType)); 348 | } 349 | 350 | void SSDPDeviceClass::setName(const char *name) { 351 | strlcpy(m_friendlyName, name, sizeof(m_friendlyName)); 352 | } 353 | 354 | void SSDPDeviceClass::setURL(const char *url) { 355 | strlcpy(m_presentationURL, url, sizeof(m_presentationURL)); 356 | } 357 | 358 | void SSDPDeviceClass::setSerialNumber(const char *serialNumber) { 359 | strlcpy(m_serialNumber, serialNumber, sizeof(m_serialNumber)); 360 | } 361 | 362 | void SSDPDeviceClass::setSerialNumber(const uint32_t serialNumber) { 363 | snprintf(m_serialNumber, sizeof(uint32_t) * 2 + 1, "%08X", serialNumber); 364 | } 365 | 366 | void SSDPDeviceClass::setModelName(const char *name) { 367 | strlcpy(m_modelName, name, sizeof(m_modelName)); 368 | } 369 | 370 | void SSDPDeviceClass::setModelNumber(const char *num) { 371 | strlcpy(m_modelNumber, num, sizeof(m_modelNumber)); 372 | } 373 | 374 | void SSDPDeviceClass::setModelURL(const char *url) { 375 | strlcpy(m_modelURL, url, sizeof(m_modelURL)); 376 | } 377 | 378 | void SSDPDeviceClass::setManufacturer(const char *name) { 379 | strlcpy(m_manufacturer, name, sizeof(m_manufacturer)); 380 | } 381 | 382 | void SSDPDeviceClass::setManufacturerURL(const char *url) { 383 | strlcpy(m_manufacturerURL, url, sizeof(m_manufacturerURL)); 384 | } 385 | 386 | void SSDPDeviceClass::setTTL(const uint8_t ttl) { 387 | m_ttl = ttl; 388 | } 389 | 390 | SSDPDeviceClass SSDPDevice; 391 | -------------------------------------------------------------------------------- /SSDPDevice.h: -------------------------------------------------------------------------------- 1 | // SSDPDevice.h 2 | // based on https://github.com/esp8266/Arduino/issues/2283 3 | // https://github.com/esp8266/Arduino/files/980894/SSDPDevice.zip 4 | // by Pawel Dino 5 | 6 | #ifndef _SSDPDEVICE_h 7 | #define _SSDPDEVICE_h 8 | 9 | 10 | #ifdef ESP8266 11 | #include 12 | #include 13 | #endif 14 | 15 | #ifdef ESP32 16 | #include 17 | #include 18 | #endif 19 | 20 | #define pip41(ipaddr) ((u16_t)(((u8_t*)(ipaddr))[0])) 21 | #define pip42(ipaddr) ((u16_t)(((u8_t*)(ipaddr))[1])) 22 | #define pip43(ipaddr) ((u16_t)(((u8_t*)(ipaddr))[2])) 23 | #define pip44(ipaddr) ((u16_t)(((u8_t*)(ipaddr))[3])) 24 | 25 | 26 | #define LIP2STR(ipaddr) pip41(ipaddr), \ 27 | pip42(ipaddr), \ 28 | pip43(ipaddr), \ 29 | pip44(ipaddr) 30 | 31 | 32 | #define SSDP_INTERVAL 1200 33 | #define SSDP_PORT 1900 34 | //#define SSDP_METHOD_SIZE 10 35 | //#define SSDP_URI_SIZE 2 36 | //#define SSDP_BUFFER_SIZE 64 37 | #define SSDP_MULTICAST_TTL 2 38 | 39 | #define SSDP_QUEUE_SIZE 21 40 | 41 | static const IPAddress SSDP_MULTICAST_ADDR(239, 255, 255, 250); 42 | 43 | #define SSDP_UUID_SIZE 37 44 | #define SSDP_SCHEMA_URL_SIZE 64 45 | #define SSDP_DEVICE_TYPE_SIZE 64 46 | #define SSDP_FRIENDLY_NAME_SIZE 64 47 | #define SSDP_SERIAL_NUMBER_SIZE 32 48 | #define SSDP_PRESENTATION_URL_SIZE 128 49 | #define SSDP_MODEL_NAME_SIZE 64 50 | #define SSDP_MODEL_URL_SIZE 128 51 | #define SSDP_MODEL_VERSION_SIZE 32 52 | #define SSDP_MANUFACTURER_SIZE 64 53 | #define SSDP_MANUFACTURER_URL_SIZE 128 54 | 55 | static const char* PROGMEM SSDP_RESPONSE_TEMPLATE = 56 | "HTTP/1.1 200 OK\r\n" 57 | "EXT:\r\n"; 58 | 59 | static const char* PROGMEM SSDP_NOTIFY_ALIVE_TEMPLATE = 60 | "NOTIFY * HTTP/1.1\r\n" 61 | "HOST: 239.255.255.250:1900\r\n" 62 | "NTS: ssdp:alive\r\n"; 63 | 64 | static const char* PROGMEM SSDP_NOTIFY_UPDATE_TEMPLATE = 65 | "NOTIFY * HTTP/1.1\r\n" 66 | "HOST: 239.255.255.250:1900\r\n" 67 | "NTS: ssdp:update\r\n"; 68 | 69 | static const char* PROGMEM SSDP_PACKET_TEMPLATE = 70 | "%s" // _ssdp_response_template / _ssdp_notify_template 71 | "CACHE-CONTROL: max-age=%u\r\n" // SSDP_INTERVAL 72 | "SERVER: UPNP/1.1 %s/%s\r\n" // m_modelName, m_modelNumber 73 | "USN: %s%s%s\r\n" // m_uuid 74 | "%s: %s\r\n" // "NT" or "ST", m_deviceType 75 | "LOCATION: http://%u.%u.%u.%u:%u/%s\r\n" // WiFi.localIP(), m_port, m_schemaURL 76 | "\r\n"; 77 | 78 | static const char* PROGMEM SSDP_SCHEMA_TEMPLATE = 79 | "HTTP/1.1 200 OK\r\n" 80 | "Content-Type: text/xml\r\n" 81 | "Connection: close\r\n" 82 | "Access-Control-Allow-Origin: *\r\n" 83 | "\r\n" 84 | "" 85 | "" 86 | "" 87 | "1" 88 | "0" 89 | "" 90 | "http://%u.%u.%u.%u:%u/%s" // WiFi.localIP(), _port 91 | "" 92 | "%s" 93 | "%s" 94 | "%s" 95 | "%s" 96 | "%s" 97 | "%s" 98 | "%s" 99 | "%s" 100 | "%s" 101 | "uuid:%s" 102 | "" 103 | // "" 104 | // "" 105 | // "image/png" 106 | // "48" 107 | // "48" 108 | // "24" 109 | // "icon48.png" 110 | // "" 111 | // "" 112 | // "image/png" 113 | // "120" 114 | // "120" 115 | // "24" 116 | // "icon120.png" 117 | // "" 118 | // "" 119 | "\r\n" 120 | "\r\n"; 121 | 122 | typedef enum { 123 | NOTIFY_ALIVE_INIT, 124 | NOTIFY_ALIVE, 125 | NOTIFY_UPDATE, 126 | RESPONSE 127 | } ssdp_message_t; 128 | 129 | typedef enum { 130 | ROOT_FOR_ALL, 131 | ROOT_BY_UUID, 132 | ROOT_BY_TYPE 133 | } ssdp_udn_t; 134 | 135 | typedef struct { 136 | unsigned long time; 137 | 138 | ssdp_message_t type; 139 | ssdp_udn_t udn; 140 | uint32_t address; 141 | uint16_t port; 142 | } ssdp_send_parameters_t; 143 | 144 | class SSDPDeviceClass { 145 | private: 146 | WiFiUDP *m_server; 147 | 148 | IPAddress m_last; 149 | 150 | char m_schemaURL[SSDP_SCHEMA_URL_SIZE]; 151 | char m_uuid[SSDP_UUID_SIZE]; 152 | char m_deviceType[SSDP_DEVICE_TYPE_SIZE]; 153 | char m_friendlyName[SSDP_FRIENDLY_NAME_SIZE]; 154 | char m_serialNumber[SSDP_SERIAL_NUMBER_SIZE]; 155 | char m_presentationURL[SSDP_PRESENTATION_URL_SIZE]; 156 | char m_manufacturer[SSDP_MANUFACTURER_SIZE]; 157 | char m_manufacturerURL[SSDP_MANUFACTURER_URL_SIZE]; 158 | char m_modelName[SSDP_MODEL_NAME_SIZE]; 159 | char m_modelURL[SSDP_MODEL_URL_SIZE]; 160 | char m_modelNumber[SSDP_MODEL_VERSION_SIZE]; 161 | 162 | uint16_t m_port; 163 | uint8_t m_ttl; 164 | 165 | ssdp_send_parameters_t m_queue[SSDP_QUEUE_SIZE]; 166 | protected: 167 | bool readLine(String &value); 168 | bool readKeyValue(String &key, String &value); 169 | 170 | void postNotifyALive(); 171 | void postNotifyUpdate(); 172 | void postResponse(long mx); 173 | void postResponse(ssdp_udn_t udn, long mx); 174 | void post(ssdp_message_t type, ssdp_udn_t udn, IPAddress address, uint16_t port, unsigned long time); 175 | 176 | void send(ssdp_send_parameters_t *parameters); 177 | public: 178 | SSDPDeviceClass(); 179 | 180 | void update(); 181 | 182 | void schema(WiFiClient client); 183 | 184 | void handleClient(); 185 | 186 | void setDeviceType(const String& deviceType) { setDeviceType(deviceType.c_str()); } 187 | void setDeviceType(const char *deviceType); 188 | void setName(const String& name) { setName(name.c_str()); } 189 | void setName(const char *name); 190 | void setURL(const String& url) { setURL(url.c_str()); } 191 | void setURL(const char *url); 192 | void setSchemaURL(const String& url) { setSchemaURL(url.c_str()); } 193 | void setSchemaURL(const char *url); 194 | void setSerialNumber(const String& serialNumber) { setSerialNumber(serialNumber.c_str()); } 195 | void setSerialNumber(const char *serialNumber); 196 | void setSerialNumber(const uint32_t serialNumber); 197 | void setModelName(const String& name) { setModelName(name.c_str()); } 198 | void setModelName(const char *name); 199 | void setModelNumber(const String& num) { setModelNumber(num.c_str()); } 200 | void setModelNumber(const char *num); 201 | void setModelURL(const String& url) { setModelURL(url.c_str()); } 202 | void setModelURL(const char *url); 203 | void setManufacturer(const String& name) { setManufacturer(name.c_str()); } 204 | void setManufacturer(const char *name); 205 | void setManufacturerURL(const String& url) { setManufacturerURL(url.c_str()); } 206 | void setManufacturerURL(const char *url); 207 | void setHTTPPort(uint16_t port); 208 | void setTTL(uint8_t ttl); 209 | }; 210 | 211 | extern SSDPDeviceClass SSDPDevice; 212 | 213 | #endif 214 | -------------------------------------------------------------------------------- /SSDPinNetwork.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gitpeut/esp32SSDP/ff63b12dc8aed30899d74b32d5e9f69b1f2f4539/SSDPinNetwork.PNG -------------------------------------------------------------------------------- /esp32SSDP.ino: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "update_server.h" 5 | #include "wifi_ss.h" 6 | #include "SSDPDevice.h" 7 | 8 | const char* host = "esesdepe"; 9 | 10 | WebServer server(80); 11 | 12 | 13 | /*-----------------------------------------------------------------------------------*/ 14 | /* 15 | * setup function 16 | */ 17 | 18 | char *nothing = "Hello, SSDP test. updater test is here"; 19 | 20 | void setup(void) { 21 | Serial.begin(115200); 22 | 23 | wifi_begin(); 24 | 25 | update_begin( &server); 26 | 27 | server.on("/", HTTP_GET, []() { 28 | server.send(200, "text/html", nothing); 29 | }); 30 | 31 | server.on("/reset", HTTP_GET, []() { 32 | server.send(200, "text/plain", "Resetting..."); 33 | delay(3000); 34 | ESP.restart(); 35 | }); 36 | 37 | server.on("/description.xml", HTTP_GET, [](){ 38 | SSDPDevice.schema( server.client()); 39 | }); 40 | 41 | SSDPDevice.setName( host ); 42 | SSDPDevice.setDeviceType("urn:schemas-upnp-org:device:BinaryLight:1"); 43 | SSDPDevice.setSchemaURL("description.xml"); 44 | SSDPDevice.setSerialNumber(ESP.getEfuseMac()); 45 | SSDPDevice.setURL("/"); 46 | SSDPDevice.setModelName(host); 47 | SSDPDevice.setModelNumber("1"); 48 | SSDPDevice.setManufacturer("Peut"); 49 | SSDPDevice.setManufacturerURL("http://www.peut.org/"); 50 | 51 | 52 | 53 | server.begin(); 54 | } 55 | 56 | void loop(void) { 57 | server.handleClient(); 58 | SSDPDevice.handleClient(); 59 | 60 | delay(1); 61 | } 62 | -------------------------------------------------------------------------------- /update_server.h: -------------------------------------------------------------------------------- 1 | #ifndef UPDATE_SERVER_H 2 | #define UPDATE_SERVER_H 3 | 4 | #include 5 | #include 6 | 7 | void update_begin(WebServer *server); 8 | void update_ask(); 9 | void update_progress(); 10 | void update_end(); 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /update_server.ino: -------------------------------------------------------------------------------- 1 | #include "update_server.h" 2 | 3 | /*-----------------------------------------------------------------------------------*/ 4 | 5 | const char* updatepage = 6 | "\n\\ 29 |

\n\\ 30 | \n\\ 31 | \n\\ 32 |
\n\\ 33 |
\n"; 34 | 35 | /*-----------------------------------------------------------------------------------*/ 36 | WebServer *update_server; 37 | 38 | void update_begin(WebServer *server){ 39 | update_server = server; 40 | update_server->on("/update", HTTP_GET, update_ask ); 41 | update_server->on("/update", HTTP_POST, update_end, update_progress ); 42 | 43 | } 44 | 45 | /*-----------------------------------------------------------------------------------*/ 46 | 47 | void update_ask(){ 48 | update_server->sendHeader("Connection", "close"); 49 | update_server->send(200, "text/html", updatepage ); 50 | } 51 | 52 | /*-----------------------------------------------------------------------------------*/ 53 | 54 | void update_progress(){ 55 | static int written_size=0; 56 | 57 | HTTPUpload& upload = update_server->upload(); 58 | 59 | if (upload.status == UPLOAD_FILE_START) { 60 | Serial.printf("Update: %s\n", upload.filename.c_str()); 61 | if (!Update.begin(UPDATE_SIZE_UNKNOWN)) { //start with max available size 62 | Update.printError(Serial); 63 | } 64 | } else if (upload.status == UPLOAD_FILE_WRITE ) { 65 | /* flashing firmware to ESP*/ 66 | //written_size += upload.currentSize; 67 | //Serial.printf("Writing %d bytes, %d/%d\n", upload.currentSize, upload.totalSize, written_size ); 68 | if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) { 69 | Update.printError(Serial); 70 | } 71 | } else if (upload.status == UPLOAD_FILE_END) { 72 | if (Update.end(true)) { //true to set the size to the current progress 73 | Serial.printf("\nUpdate Success: %u\nRebooting...\n", upload.totalSize); 74 | update_server->sendHeader("Connection", "close"); 75 | update_server->send(200, "text/plain", "Upload successful, rebooting"); 76 | } else { 77 | Update.printError(Serial); 78 | update_server->send(200, "text/plain", "Upload failed"); 79 | } 80 | } 81 | } 82 | 83 | void update_end(){ 84 | update_server->sendHeader("Connection", "close"); 85 | update_server->send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK"); 86 | Serial.printf("---Update %s\n", Update.hasError() ? "FAIL" : "OK"); 87 | Serial.flush(); 88 | ESP.restart(); 89 | } 90 | -------------------------------------------------------------------------------- /wifi_ss.h: -------------------------------------------------------------------------------- 1 | #ifndef WIFI_SS_H 2 | #define WIFI_SS_H 3 | 4 | #include 5 | // made a directory wificredentials in libraries and define ssid and password in wificredentials.h 6 | #include 7 | 8 | void wifi_begin(); 9 | void wifi_event ( WiFiEvent_t event ); 10 | 11 | 12 | #endif 13 | -------------------------------------------------------------------------------- /wifi_ss.ino: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include "wifi_ss.h" 4 | 5 | 6 | 7 | bool wifi_disconnecting = false; 8 | 9 | /*--------------------------------------------------*/ 10 | 11 | void wifi_begin(){ 12 | 13 | WiFi.mode(WIFI_STA); 14 | WiFi.onEvent( wifi_event ); 15 | // Wait for connection 16 | for ( int i=3, kill = 0; WiFi.status() != WL_CONNECTED; ++i, ++kill ) { 17 | if ( i > 2 ) { 18 | WiFi.begin(ssid, password); 19 | i = 0; 20 | } 21 | delay(500); 22 | Serial.print("."); 23 | if ( kill > 20){ 24 | Serial.flush(); 25 | ESP.restart(); 26 | } 27 | } 28 | wifi_disconnecting = false; 29 | 30 | Serial.print("Connected to "); 31 | Serial.println(ssid); 32 | Serial.print("IP address: "); 33 | Serial.println(WiFi.localIP()); 34 | 35 | } 36 | 37 | /*--------------------------------------------------*/ 38 | 39 | void wifi_event ( WiFiEvent_t event ){ 40 | 41 | int do_reconnect = 1; 42 | 43 | switch( event ){ 44 | case SYSTEM_EVENT_STA_DISCONNECTED: 45 | Serial.println("Disconnected from WiFi access point"); 46 | break; 47 | case SYSTEM_EVENT_STA_LOST_IP: 48 | Serial.println("Lost IP address and IP address is reset to 0"); 49 | break; 50 | case 200: 51 | Serial.println("Beacon time out"); 52 | break; 53 | case 202: 54 | Serial.println("WiFi Auth fail"); 55 | break; 56 | default: 57 | do_reconnect = 0; 58 | } 59 | 60 | if ( do_reconnect && ! wifi_disconnecting ){ 61 | wifi_disconnecting = true; 62 | WiFi.disconnect(); 63 | 64 | wifi_begin(); 65 | } 66 | 67 | } 68 | 69 | /*--------------------------------------------------*/ 70 | --------------------------------------------------------------------------------