Update SSDP library with latest

This commit is contained in:
Luc 2020-06-18 12:44:36 +02:00
parent 80d63de725
commit aadb8b01f4
14 changed files with 1047 additions and 553 deletions

View File

@ -1,479 +0,0 @@
/*
ESP32 Simple Service Discovery
Copyright (c) 2015 Hristo Gochkov
Original (Arduino) version by Filippo Sallemi, July 23, 2014.
Can be found at: https://github.com/nomadnt/uSSDP
License (MIT license):
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifdef ARDUINO_ARCH_ESP32
#include <functional>
#include "ESP32SSDP.h"
#include "WiFiUdp.h"
#include <lwip/ip_addr.h>
//#define DEBUG_SSDP Serial
#define SSDP_INTERVAL 1200
#define SSDP_PORT 1900
#define SSDP_METHOD_SIZE 10
#define SSDP_URI_SIZE 2
#define SSDP_BUFFER_SIZE 64
#define SSDP_MULTICAST_TTL 2
static const IPAddress SSDP_MULTICAST_ADDR(239, 255, 255, 250);
static const char _ssdp_response_template[] PROGMEM =
"HTTP/1.1 200 OK\r\n"
"EXT:\r\n";
static const char _ssdp_notify_template[] PROGMEM =
"NOTIFY * HTTP/1.1\r\n"
"HOST: 239.255.255.250:1900\r\n"
"NTS: ssdp:alive\r\n";
static const char _ssdp_packet_template[] PROGMEM =
"%s" // _ssdp_response_template / _ssdp_notify_template
"CACHE-CONTROL: max-age=%u\r\n" // SSDP_INTERVAL
"SERVER: Arduino/1.0 UPNP/1.1 %s/%s\r\n" // _modelName, _modelNumber
"USN: uuid:%s\r\n" // _uuid
"%s: %s\r\n" // "NT" or "ST", _deviceType
"LOCATION: http://%u.%u.%u.%u:%u/%s\r\n" // WiFi.localIP(), _port, _schemaURL
"\r\n";
static const char _ssdp_schema_template[] PROGMEM =
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/xml\r\n"
"Connection: close\r\n"
"Access-Control-Allow-Origin: *\r\n"
"\r\n"
"<?xml version=\"1.0\"?>"
"<root xmlns=\"urn:schemas-upnp-org:device-1-0\">"
"<specVersion>"
"<major>1</major>"
"<minor>0</minor>"
"</specVersion>"
"<URLBase>http://%u.%u.%u.%u:%u/</URLBase>" // WiFi.localIP(), _port
"<device>"
"<deviceType>%s</deviceType>"
"<friendlyName>%s</friendlyName>"
"<presentationURL>%s</presentationURL>"
"<serialNumber>%s</serialNumber>"
"<modelName>%s</modelName>"
"<modelNumber>%s</modelNumber>"
"<modelURL>%s</modelURL>"
"<manufacturer>%s</manufacturer>"
"<manufacturerURL>%s</manufacturerURL>"
"<UDN>uuid:%s</UDN>"
"</device>"
// "<iconList>"
// "<icon>"
// "<mimetype>image/png</mimetype>"
// "<height>48</height>"
// "<width>48</width>"
// "<depth>24</depth>"
// "<url>icon48.png</url>"
// "</icon>"
// "<icon>"
// "<mimetype>image/png</mimetype>"
// "<height>120</height>"
// "<width>120</width>"
// "<depth>24</depth>"
// "<url>icon120.png</url>"
// "</icon>"
// "</iconList>"
"</root>\r\n"
"\r\n";
struct SSDPTimer {
ETSTimer timer;
};
SSDPClass::SSDPClass() :
_server(0),
_timer(0),
_port(80),
_ttl(SSDP_MULTICAST_TTL),
_respondToPort(0),
_pending(false),
_delay(0),
_process_time(0),
_notify_time(0)
{
_uuid[0] = '\0';
_modelNumber[0] = '\0';
sprintf(_deviceType, "urn:schemas-upnp-org:device:Basic:1");
_friendlyName[0] = '\0';
_presentationURL[0] = '\0';
_serialNumber[0] = '\0';
_modelName[0] = '\0';
_modelURL[0] = '\0';
_manufacturer[0] = '\0';
_manufacturerURL[0] = '\0';
sprintf(_schemaURL, "ssdp/schema.xml");
}
SSDPClass::~SSDPClass(){
end();
}
void SSDPClass::end(){
if(!_server) {
return;
}
#ifdef DEBUG_SSDP
DEBUG_SSDP.printf_P(PSTR("SSDP end ... "));
#endif
// undo all initializations done in begin(), in reverse order
_stopTimer();
_server->stop();
delete (_server);
_server = 0;
}
IPAddress SSDPClass::localIP(){
tcpip_adapter_ip_info_t ip;
if (WiFi.getMode() == WIFI_STA) {
if (tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &ip)) {
return IPAddress();
}
} else if (WiFi.getMode() == WIFI_OFF) {
if (tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_ETH, &ip)) {
return IPAddress();
}
}
return IPAddress(ip.ip.addr);
}
bool SSDPClass::begin(){
_pending = false;
end();
uint32_t chipId = ((uint16_t) (ESP.getEfuseMac() >> 32));
sprintf(_uuid, "38323636-4558-4dda-9188-cda0e6%02x%02x%02x",
(uint16_t) ((chipId >> 16) & 0xff),
(uint16_t) ((chipId >> 8) & 0xff),
(uint16_t) chipId & 0xff );
assert(nullptr == _server);
_server = new WiFiUDP;
#ifdef DEBUG_SSDP
DEBUG_SSDP.printf("SSDP UUID: %s\n", (char *)_uuid);
#endif
_server = new WiFiUDP;
if (!(_server->beginMulticast(IPAddress(SSDP_MULTICAST_ADDR), SSDP_PORT))) {
#ifdef DEBUG_SSDP
DEBUG_SSDP.println("Error begin");
#endif
return false;
}
_startTimer();
return true;
}
void SSDPClass::_send(ssdp_method_t method){
char buffer[1460];
IPAddress ip = localIP();
char valueBuffer[strlen_P(_ssdp_notify_template)+1];
strcpy_P(valueBuffer, (method == NONE)?_ssdp_response_template:_ssdp_notify_template);
int len = snprintf_P(buffer, sizeof(buffer),
_ssdp_packet_template,
valueBuffer,
SSDP_INTERVAL,
_modelName, _modelNumber,
_uuid,
(method == NONE)?"ST":"NT",
_deviceType,
ip[0], ip[1], ip[2], ip[3], _port, _schemaURL
);
if(len < 0) return;
IPAddress remoteAddr;
uint16_t remotePort;
if(method == NONE) {
remoteAddr = _respondToAddr;
remotePort = _respondToPort;
#ifdef DEBUG_SSDP
DEBUG_SSDP.print("Sending Response to ");
#endif
} else {
remoteAddr = IPAddress(SSDP_MULTICAST_ADDR);
remotePort = SSDP_PORT;
#ifdef DEBUG_SSDP
DEBUG_SSDP.println("Sending Notify to ");
#endif
}
#ifdef DEBUG_SSDP
DEBUG_SSDP.print(remoteAddr);
DEBUG_SSDP.print(":");
DEBUG_SSDP.println(remotePort);
#endif
_server->beginPacket(remoteAddr, remotePort);
_server->println(buffer);
_server->endPacket();
}
void SSDPClass::schema(WiFiClient client){
IPAddress ip = localIP();
char buffer[strlen_P(_ssdp_schema_template)+1];
strcpy_P(buffer, _ssdp_schema_template);
client.printf(buffer,
ip[0], ip[1], ip[2], ip[3], _port,
_deviceType,
_friendlyName,
_presentationURL,
_serialNumber,
_modelName,
_modelNumber,
_modelURL,
_manufacturer,
_manufacturerURL,
_uuid
);
}
void SSDPClass::_update(){
int nbBytes =0;
char * packetBuffer = nullptr;
if(!_pending && _server) {
ssdp_method_t method = NONE;
nbBytes= _server->parsePacket();
typedef enum {METHOD, URI, PROTO, KEY, VALUE, ABORT} states;
states state = METHOD;
typedef enum {START, MAN, ST, MX} headers;
headers header = START;
uint8_t cursor = 0;
uint8_t cr = 0;
char buffer[SSDP_BUFFER_SIZE] = {0};
packetBuffer = new char[nbBytes +1];
int message_size=_server->read(packetBuffer,nbBytes);
int process_pos = 0;
packetBuffer[message_size]='\0';
_respondToAddr = _server->remoteIP();
_respondToPort = _server->remotePort();
#ifdef DEBUG_SSDP
if (message_size) {
DEBUG_SSDP.println("****************************************************");
DEBUG_SSDP.println(_server->remoteIP());
DEBUG_SSDP.println(packetBuffer);
DEBUG_SSDP.println("****************************************************");
}
#endif
while(process_pos < message_size){
char c = packetBuffer[process_pos];
process_pos++;
(c == '\r' || c == '\n') ? cr++ : cr = 0;
#ifdef DEBUG_SSDP
if ((c == '\r' || c == '\n') && (cr < 2)) DEBUG_SSDP.println(buffer);
#endif
switch(state){
case METHOD:
if(c == ' '){
if(strcmp(buffer, "M-SEARCH") == 0) method = SEARCH;
if(method == NONE) state = ABORT;
else state = URI;
cursor = 0;
} else if(cursor < SSDP_METHOD_SIZE - 1){ buffer[cursor++] = c; buffer[cursor] = '\0'; }
break;
case URI:
if(c == ' '){
if(strcmp(buffer, "*")) state = ABORT;
else state = PROTO;
cursor = 0;
} else if(cursor < SSDP_URI_SIZE - 1){ buffer[cursor++] = c; buffer[cursor] = '\0'; }
break;
case PROTO:
if(cr == 2){ state = KEY; cursor = 0; }
break;
case KEY:
if(cr == 4){ _pending = true; _process_time = millis(); }
else if(c == ' '){ cursor = 0; state = VALUE; }
else if(c != '\r' && c != '\n' && c != ':' && cursor < SSDP_BUFFER_SIZE - 1){ buffer[cursor++] = c; buffer[cursor] = '\0'; }
break;
case VALUE:
if(cr == 2){
switch(header){
case START:
break;
case MAN:
#ifdef DEBUG_SSDP
DEBUG_SSDP.printf("MAN: %s\n", (char *)buffer);
#endif
break;
case ST:
if(strcmp(buffer, "ssdp:all")){
state = ABORT;
#ifdef DEBUG_SSDP
DEBUG_SSDP.printf("REJECT: %s\n", (char *)buffer);
#endif
}
// if the search type matches our type, we should respond instead of ABORT
if(strcasecmp(buffer, _deviceType) == 0){
_pending = true;
_process_time = 0;
#ifdef DEBUG_SSDP
DEBUG_SSDP.println("the search type matches our type");
#endif
state = KEY;
}
break;
case MX:
_delay = random(0, atoi(buffer)) * 1000L;
break;
}
if(state != ABORT){ state = KEY; header = START; cursor = 0; }
} else if(c != '\r' && c != '\n'){
if(header == START){
if(strncmp(buffer, "MA", 2) == 0) header = MAN;
else if(strcmp(buffer, "ST") == 0) header = ST;
else if(strcmp(buffer, "MX") == 0) header = MX;
}
if(cursor < SSDP_BUFFER_SIZE - 1){ buffer[cursor++] = c; buffer[cursor] = '\0'; }
}
break;
case ABORT:
_pending = false; _delay = 0;
break;
}
}
}
if(packetBuffer) delete packetBuffer;
if(_pending && (millis() - _process_time) > _delay){
_pending = false; _delay = 0;
#ifdef DEBUG_SSDP
DEBUG_SSDP.println("Send None");
#endif
_send(NONE);
} else if(_notify_time == 0 || (millis() - _notify_time) > (SSDP_INTERVAL * 1000L)){
_notify_time = millis();
#ifdef DEBUG_SSDP
DEBUG_SSDP.println("Send Notify");
#endif
_send(NOTIFY);
} else {
#ifdef DEBUG_SSDP
DEBUG_SSDP.println("Do not sent");
#endif
}
if (_pending) {
_server->flush();
}
}
void SSDPClass::setSchemaURL(const char *url){
strlcpy(_schemaURL, url, sizeof(_schemaURL));
}
void SSDPClass::setHTTPPort(uint16_t port){
_port = port;
}
void SSDPClass::setDeviceType(const char *deviceType){
strlcpy(_deviceType, deviceType, sizeof(_deviceType));
}
void SSDPClass::setName(const char *name){
strlcpy(_friendlyName, name, sizeof(_friendlyName));
}
void SSDPClass::setURL(const char *url){
strlcpy(_presentationURL, url, sizeof(_presentationURL));
}
void SSDPClass::setSerialNumber(const char *serialNumber){
strlcpy(_serialNumber, serialNumber, sizeof(_serialNumber));
}
void SSDPClass::setSerialNumber(const uint32_t serialNumber){
snprintf(_serialNumber, sizeof(uint32_t)*2+1, "%08X", serialNumber);
}
void SSDPClass::setModelName(const char *name){
strlcpy(_modelName, name, sizeof(_modelName));
}
void SSDPClass::setModelNumber(const char *num){
strlcpy(_modelNumber, num, sizeof(_modelNumber));
}
void SSDPClass::setModelURL(const char *url){
strlcpy(_modelURL, url, sizeof(_modelURL));
}
void SSDPClass::setManufacturer(const char *name){
strlcpy(_manufacturer, name, sizeof(_manufacturer));
}
void SSDPClass::setManufacturerURL(const char *url){
strlcpy(_manufacturerURL, url, sizeof(_manufacturerURL));
}
void SSDPClass::setTTL(const uint8_t ttl){
_ttl = ttl;
}
void SSDPClass::_onTimerStatic(SSDPClass* self) {
#ifdef DEBUG_SSDP
DEBUG_SSDP.println("Update");
#endif
self->_update();
}
void SSDPClass::_startTimer() {
_stopTimer();
_timer= new SSDPTimer();
ETSTimer* tm = &(_timer->timer);
const int interval = 1000;
ets_timer_disarm(tm);
ets_timer_setfn(tm, reinterpret_cast<ETSTimerFunc*>(&SSDPClass::_onTimerStatic), reinterpret_cast<void*>(this));
ets_timer_arm(tm, interval, 1 /* repeat */);
}
void SSDPClass::_stopTimer() {
if(!_timer){
return;
}
ETSTimer* tm = &(_timer->timer);
ets_timer_disarm(tm);
delete _timer;
_timer = nullptr;
}
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SSDP)
SSDPClass SSDP;
#endif
#endif

View File

@ -1,52 +0,0 @@
#include <WiFi.h>
#include <WebServer.h>
#include <ESP32SSDP.h>
const char* ssid = "********";
const char* password = "********";
WebServer HTTP(80);
void setup() {
Serial.begin(115200);
Serial.println();
Serial.println("Starting WiFi...");
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
if(WiFi.waitForConnectResult() == WL_CONNECTED){
Serial.printf("Starting HTTP...\n");
HTTP.on("/index.html", HTTP_GET, [](){
HTTP.send(200, "text/plain", "Hello World!");
});
HTTP.on("/description.xml", HTTP_GET, [](){
SSDP.schema(HTTP.client());
});
HTTP.begin();
Serial.printf("Starting SSDP...\n");
SSDP.setSchemaURL("description.xml");
SSDP.setHTTPPort(80);
SSDP.setName("Philips hue clone");
SSDP.setSerialNumber("001788102201");
SSDP.setURL("index.html");
SSDP.setModelName("Philips hue bridge 2012");
SSDP.setModelNumber("929000226503");
SSDP.setModelURL("http://www.meethue.com");
SSDP.setManufacturer("Royal Philips Electronics");
SSDP.setManufacturerURL("http://www.philips.com");
SSDP.setDeviceType("upnp:rootdevice"); //to appear as root device
SSDP.begin();
Serial.printf("Ready!\n");
} else {
Serial.printf("WiFi Failed\n");
while(1) delay(100);
}
}
void loop() {
HTTP.handleClient();
delay(1);
}

View File

@ -0,0 +1 @@
style=otbs

View File

@ -0,0 +1,64 @@
dist: xenial
sudo: require
language: python
python:
- "3.7"
os:
- linux
cache:
pip: true
directories:
- "~/.platformio"
- $HOME/astyle
install:
- pip install -U platformio
before_script:
- platformio update
- wget http://downloads.arduino.cc/arduino-1.8.5-linux64.tar.xz
- tar xf arduino-1.8.5-linux64.tar.xz
- mv arduino-1.8.5 $HOME/arduino_ide
- cd $HOME/arduino_ide/hardware
- mkdir esp32
- cd esp32
- git clone https://github.com/espressif/arduino-esp32.git esp32
- cd esp32
- git submodule update --init --recursive
- cd tools
- python get.py
- cd $TRAVIS_BUILD_DIR
- cp -r $TRAVIS_BUILD_DIR $HOME/arduino_ide/libraries/
- sh test/install_astyle.sh
script:
- cd $TRAVIS_BUILD_DIR
- export ARTISTIC_STYLE_OPTIONS=".astylerc"
- astyle -Q `find . -name *.cpp -o -name *.ino -o -name *.h` > astyle.out
- TEST=$(cat astyle.out | wc -l)
- |
if [[ $TEST -ne 0 ]]; then
cat astyle.out
git --no-pager diff
echo "Please fix style issues as shown above"
exit 1
fi
- source command.sh
- export PATH="$HOME/arduino_ide:$PATH"
- rm -f $HOME/.arduino15/preferences.txt
- arduino --board esp32:esp32:esp32:PartitionScheme=min_spiffs,FlashFreq=80,PSRAM=disabled,CPUFreq=240,FlashMode=qio,FlashSize=4M,DebugLevel=none --pref compiler.warning_level=all --save-prefs
- build_sketch $TRAVIS_BUILD_DIR/examples/SSDP/SSDP.ino
- rm -fr $HOME/arduino_ide
- rm -fr $HOME/.arduino15
- cp $TRAVIS_BUILD_DIR/test/platformio.ini $TRAVIS_BUILD_DIR/examples/SSDP/
- cd $TRAVIS_BUILD_DIR/examples/SSDP/
- platformio run
notifications:
email:
on_success: change
on_failure: change

View File

@ -0,0 +1,710 @@
/*
ESP32 Simple Service Discovery
Copyright (c) 2015 Hristo Gochkov
Original (Arduino) version by Filippo Sallemi, July 23, 2014.
Can be found at: https://github.com/nomadnt/uSSDP
License (MIT license):
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#ifdef ARDUINO_ARCH_ESP32
#include <functional>
#include "ESP32SSDP.h"
#include "WiFiUdp.h"
#include <lwip/ip_addr.h>
//#define DEBUG_SSDP Serial
#define SSDP_INTERVAL 1200
#define SSDP_PORT 1900
#define SSDP_METHOD_SIZE 10
#define SSDP_URI_SIZE 2
#define SSDP_BUFFER_SIZE 64
#define SSDP_MULTICAST_TTL 2
static const IPAddress SSDP_MULTICAST_ADDR(239, 255, 255, 250);
#define SSDP_UUID_ROOT "38323636-4558-4dda-9188-cda0e6"
static const char _ssdp_response_template[] PROGMEM =
"HTTP/1.1 200 OK\r\n"
"EXT:\r\n";
static const char _ssdp_notify_template[] PROGMEM =
"NOTIFY * HTTP/1.1\r\n"
"HOST: 239.255.255.250:1900\r\n"
"NTS: ssdp:alive\r\n";
static const char _ssdp_packet_template[] PROGMEM =
"%s" // _ssdp_response_template / _ssdp_notify_template
"CACHE-CONTROL: max-age=%u\r\n" // _interval
"SERVER: %s UPNP/1.1 %s/%s\r\n" // _servername, _modelName, _modelNumber
"USN: uuid:%s%s\r\n" // _uuid, _usn_suffix
"%s: %s\r\n" // "NT" or "ST", _deviceType
"LOCATION: http://%u.%u.%u.%u:%u/%s\r\n" // WiFi.localIP(), _port, _schemaURL
"\r\n";
static const char _ssdp_schema_template[] PROGMEM =
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/xml\r\n"
"Connection: close\r\n"
"Access-Control-Allow-Origin: *\r\n"
"\r\n"
"<?xml version=\"1.0\"?>"
"<root xmlns=\"urn:schemas-upnp-org:device-1-0\">"
"<specVersion>"
"<major>1</major>"
"<minor>0</minor>"
"</specVersion>"
"<URLBase>http://%u.%u.%u.%u:%u/</URLBase>" // WiFi.localIP(), _port
"<device>"
"<deviceType>%s</deviceType>"
"<friendlyName>%s</friendlyName>"
"<presentationURL>%s</presentationURL>"
"<serialNumber>%s</serialNumber>"
"<modelName>%s</modelName>"
"<modelDescription>%s</modelDescription>"
"<modelNumber>%s</modelNumber>"
"<modelURL>%s</modelURL>"
"<manufacturer>%s</manufacturer>"
"<manufacturerURL>%s</manufacturerURL>"
"<UDN>uuid:%s</UDN>"
"<serviceList>%s</serviceList>"
"</device>"
"<iconList>%s</iconList>"
"</root>\r\n"
"\r\n";
struct SSDPTimer {
ETSTimer timer;
};
SSDPClass::SSDPClass() :
_server(0),
_timer(0),
_port(80),
_ttl(SSDP_MULTICAST_TTL),
_interval(SSDP_INTERVAL),
_replySlots{NULL},
_respondToAddr{0,0,0,0},
_respondToPort(0),
_pending(false),
_stmatch(false),
_delay(0),
_process_time(0),
_notify_time(0)
{
_uuid[0] = '\0';
_usn_suffix[0] = '\0';
_respondType[0] = '\0';
_modelNumber[0] = '\0';
sprintf(_deviceType, "urn:schemas-upnp-org:device:Basic:1");
_friendlyName[0] = '\0';
_presentationURL[0] = '\0';
_serialNumber[0] = '\0';
_modelName[0] = '\0';
_modelURL[0] = '\0';
_manufacturer[0] = '\0';
_manufacturerURL[0] = '\0';
_servername = "Arduino/1.0";
sprintf(_schemaURL, "ssdp/schema.xml");
_schema = nullptr;
}
SSDPClass::~SSDPClass()
{
end();
}
void SSDPClass::end()
{
if (_schema) {
free(_schema);
_schema = nullptr;
}
if(!_server) {
return;
}
#ifdef DEBUG_SSDP
DEBUG_SSDP.printf_P(PSTR("SSDP end ... "));
#endif
// undo all initializations done in begin(), in reverse order
_stopTimer();
_server->stop();
delete (_server);
_server = 0;
}
IPAddress SSDPClass::localIP()
{
tcpip_adapter_ip_info_t ip;
if (WiFi.getMode() == WIFI_STA) {
if (tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &ip)) {
return IPAddress();
}
} else if (WiFi.getMode() == WIFI_OFF) {
if (tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_ETH, &ip)) {
return IPAddress();
}
}
return IPAddress(ip.ip.addr);
}
void SSDPClass::setUUID(const char *uuid, bool rootonly)
{
//no sanity check is done - TBD
if (rootonly) {
uint32_t chipId = ((uint16_t) (ESP.getEfuseMac() >> 32));
sprintf(_uuid, "%s%02x%02x%02x",
uuid,
(uint16_t) ((chipId >> 16) & 0xff),
(uint16_t) ((chipId >> 8) & 0xff),
(uint16_t) chipId & 0xff );
} else {
strlcpy(_uuid, uuid,sizeof(_uuid));
}
}
bool SSDPClass::begin()
{
_pending = false;
_stmatch = false;
end();
if (strlen(_uuid) == 0) {
setUUID(SSDP_UUID_ROOT);
}
#ifdef DEBUG_SSDP
DEBUG_SSDP.printf("SSDP UUID: %s\n", (char *)_uuid);
#endif
assert(nullptr == _server);
_server = new WiFiUDP;
if (!(_server->beginMulticast(IPAddress(SSDP_MULTICAST_ADDR), SSDP_PORT))) {
#ifdef DEBUG_SSDP
DEBUG_SSDP.println("Error begin");
#endif
return false;
}
_startTimer();
return true;
}
void SSDPClass::_send(ssdp_method_t method)
{
char buffer[1460];
IPAddress ip = localIP();
char valueBuffer[strlen_P(_ssdp_notify_template)+1];
strcpy_P(valueBuffer, (method == NONE)?_ssdp_response_template:_ssdp_notify_template);
int len = snprintf_P(buffer, sizeof(buffer),
_ssdp_packet_template,
valueBuffer,
_interval,
_servername.c_str(),
_modelName, _modelNumber,
_uuid, _usn_suffix,
(method == NONE)?"ST":"NT",
_respondType,
ip[0], ip[1], ip[2], ip[3], _port, _schemaURL
);
if(len < 0) {
return;
}
IPAddress remoteAddr;
uint16_t remotePort;
if(method == NONE) {
remoteAddr = _respondToAddr;
remotePort = _respondToPort;
#ifdef DEBUG_SSDP
DEBUG_SSDP.print("Sending Response to ");
#endif
} else {
remoteAddr = IPAddress(SSDP_MULTICAST_ADDR);
remotePort = SSDP_PORT;
#ifdef DEBUG_SSDP
DEBUG_SSDP.print("Sending Notify to ");
#endif
}
#ifdef DEBUG_SSDP
DEBUG_SSDP.print(remoteAddr);
DEBUG_SSDP.print(":");
DEBUG_SSDP.println(remotePort);
#endif
_server->beginPacket(remoteAddr, remotePort);
_server->println(buffer);
#ifdef DEBUG_SSDP
DEBUG_SSDP.println("*************************TX*************************");
DEBUG_SSDP.println(buffer);
DEBUG_SSDP.println("****************************************************");
#endif
_server->endPacket();
}
const char * SSDPClass::schema()
{
uint len = strlen(_ssdp_schema_template)
+ 21 //(IP = 15) + 1 (:) + 5 (port)
+ SSDP_DEVICE_TYPE_SIZE
+ SSDP_FRIENDLY_NAME_SIZE
+ SSDP_SCHEMA_URL_SIZE
+ SSDP_SERIAL_NUMBER_SIZE
+ SSDP_MODEL_NAME_SIZE
+ _modelDescription.length()
+ SSDP_MODEL_VERSION_SIZE
+ SSDP_MODEL_URL_SIZE
+ SSDP_MANUFACTURER_SIZE
+ SSDP_MANUFACTURER_URL_SIZE
+ SSDP_UUID_SIZE
+ _services.length()
+ _icons.length();
if (_schema) {
free (_schema);
_schema = nullptr;
}
_schema = (char *)malloc(len+1);
if (_schema) {
IPAddress ip = localIP();
sprintf(_schema, _ssdp_schema_template,
ip[0], ip[1], ip[2], ip[3], _port,
_deviceType,
_friendlyName,
_presentationURL,
_serialNumber,
_modelName,
_modelDescription.c_str(),
_modelNumber,
_modelURL,
_manufacturer,
_manufacturerURL,
_uuid,
_services.c_str(),
_icons.c_str()
);
} else {
#ifdef DEBUG_SSDP
DEBUG_SSDP.println("not enough memory for schema");
#endif
}
return _schema;
}
void SSDPClass::schema(WiFiClient client)
{
client.print(schema());
}
void SSDPClass::_update()
{
int nbBytes =0;
char * packetBuffer = nullptr;
if(!_pending && _server) {
ssdp_method_t method = NONE;
nbBytes= _server->parsePacket();
typedef enum {METHOD, URI, PROTO, KEY, VALUE, ABORT} states;
states state = METHOD;
typedef enum {STRIP, START, SKIP, MAN, ST, MX} headers;
headers header = STRIP;
uint8_t cursor = 0;
uint8_t cr = 0;
char buffer[SSDP_BUFFER_SIZE] = {0};
packetBuffer = new char[nbBytes +1];
int message_size=_server->read(packetBuffer,nbBytes);
int process_pos = 0;
packetBuffer[message_size]='\0';
_respondToAddr = _server->remoteIP();
_respondToPort = _server->remotePort();
#ifdef DEBUG_SSDP
if (message_size) {
DEBUG_SSDP.println("*************************RX*************************");
DEBUG_SSDP.print(_server->remoteIP());
DEBUG_SSDP.print(":");
DEBUG_SSDP.println(_server->remotePort());
DEBUG_SSDP.println(packetBuffer);
DEBUG_SSDP.println("****************************************************");
}
#endif
while(process_pos < message_size) {
char c = packetBuffer[process_pos];
process_pos++;
(c == '\r' || c == '\n') ? cr++ : cr = 0;
switch(state) {
case METHOD:
if(c == ' ') {
if(strcmp(buffer, "M-SEARCH") == 0) {
method = SEARCH;
}
if(method == NONE) {
state = ABORT;
} else {
state = URI;
}
cursor = 0;
} else if(cursor < SSDP_METHOD_SIZE - 1) {
buffer[cursor++] = c;
buffer[cursor] = '\0';
}
break;
case URI:
if(c == ' ') {
if(strcmp(buffer, "*")) {
state = ABORT;
} else {
state = PROTO;
}
cursor = 0;
} else if(cursor < SSDP_URI_SIZE - 1) {
buffer[cursor++] = c;
buffer[cursor] = '\0';
}
break;
case PROTO:
if(cr == 2) {
state = KEY;
cursor = 0;
}
break;
case KEY:
// end of HTTP request parsing. If we find a match start reply delay.
if(cr == 4) {
if (_stmatch) {
_pending = true;
_process_time = millis();
}
} else if(c == ':') {
cursor = 0;
state = VALUE;
} else if(c != '\r' && c != '\n' && c != ' ' && cursor < SSDP_BUFFER_SIZE - 1) {
buffer[cursor++] = c;
buffer[cursor] = '\0';
}
break;
case VALUE:
if(cr == 2) {
switch(header) {
case START:
case STRIP:
case SKIP:
break;
case MAN:
#ifdef DEBUG_SSDP
DEBUG_SSDP.printf("MAN: %s\n", (char *)buffer);
#endif
break;
case ST:
// save the search term for the reply and clear usn suffix.
strlcpy(_respondType, buffer, sizeof(_respondType));
_usn_suffix[0] = '\0';
#ifdef DEBUG_SSDP
DEBUG_SSDP.printf("ST: '%s'\n",buffer);
#endif
// if looking for all or root reply with upnp:rootdevice
if(strcmp(buffer, "ssdp:all")==0 || strcmp(buffer, "upnp:rootdevice")==0) {
_stmatch = true;
// set USN suffix
strlcpy(_usn_suffix, "::upnp:rootdevice", sizeof(_usn_suffix));
#ifdef DEBUG_SSDP
DEBUG_SSDP.println("the search type matches all and root");
#endif
state = KEY;
} else
// if the search type matches our type, we should respond instead of ABORT
if(strcasecmp(buffer, _deviceType) == 0) {
_stmatch = true;
// set USN suffix to the device type
strlcpy(_usn_suffix, "::", sizeof(_usn_suffix));
strlcat(_usn_suffix, _deviceType, sizeof(_usn_suffix));
#ifdef DEBUG_SSDP
DEBUG_SSDP.println("the search type matches our type");
#endif
state = KEY;
} else {
state = ABORT;
#ifdef DEBUG_SSDP
DEBUG_SSDP.println("REJECT. The search type does not match our type");
#endif
}
break;
case MX:
// delay in ms from 0 to MX*1000 where MX is in seconds with limits.
_delay = (short)random(0, atoi(buffer) * 1000L);
if (_delay > SSDP_MAX_DELAY) {
_delay = SSDP_MAX_DELAY;
}
break;
}
if(state != ABORT) {
state = KEY;
header = STRIP;
cursor = 0;
}
} else if(c != '\r' && c != '\n') {
if(header == STRIP) {
if(c == ' ') {
break;
} else {
header = START;
}
}
if(header == START) {
if(strncmp(buffer, "MA", 2) == 0) {
header = MAN;
} else if(strcmp(buffer, "ST") == 0) {
header = ST;
} else if(strcmp(buffer, "MX") == 0) {
header = MX;
} else {
header = SKIP;
}
}
if(cursor < SSDP_BUFFER_SIZE - 1) {
buffer[cursor++] = c;
buffer[cursor] = '\0';
}
}
break;
case ABORT:
_pending = false;
_delay = 0;
break;
}
}
}
if(packetBuffer) {
delete packetBuffer;
}
// save reply in reply queue if one is pending
if(_pending) {
int i;
// Many UPNP hosts send out mulitple M-SEARCH packets at the same time to mitigate
// packet loss. Just reply to one for a given host:port.
for (i = 0; i < SSDP_MAX_REPLY_SLOTS; i++) {
if (_replySlots[i]) {
if (_replySlots[i]->_respondToPort == _respondToPort &&
_replySlots[i]->_respondToAddr == _respondToAddr
) {
// keep original delay
_delay = _replySlots[i]->_delay;
_process_time = _replySlots[i]->_process_time;
#ifdef DEBUG_SSDP
DEBUG_SSDP.printf("Remove dupe SSDP reply in slot %i.\n", i);
#endif
delete _replySlots[i];
_replySlots[i] = 0;
}
}
}
// save packet to available reply queue slot
for (i = 0; i < SSDP_MAX_REPLY_SLOTS; i++) {
if (!_replySlots[i]) {
#ifdef DEBUG_SSDP
DEBUG_SSDP.printf("Saving deferred SSDP reply to queue slot %i.\n", i);
#endif
_replySlots[i] = new ssdp_reply_slot_item_t;
_replySlots[i]->_process_time = _process_time;
_replySlots[i]->_delay = _delay;
_replySlots[i]->_respondToAddr = _respondToAddr;
_replySlots[i]->_respondToPort = _respondToPort;
strlcpy(_replySlots[i]->_respondType, _respondType, sizeof(_replySlots[i]->_respondType));
strlcpy(_replySlots[i]->_usn_suffix, _usn_suffix, sizeof(_replySlots[i]->_usn_suffix));
break;
}
}
#ifdef DEBUG_SSDP
if (i == SSDP_MAX_REPLY_SLOTS) {
DEBUG_SSDP.println("SSDP reply queue is full dropping packet.");
}
#endif
_pending = false;
_delay = 0;
}
// send any packets that are pending and overdue.
unsigned long t = millis();
bool sent = false;
for (int i = 0; i < SSDP_MAX_REPLY_SLOTS; i++) {
if (_replySlots[i]) {
// millis delay with overflow protection.
if (t - _replySlots[i]->_process_time > _replySlots[i]->_delay) {
// reply ready. restore and send.
_respondToAddr = _replySlots[i]->_respondToAddr;
_respondToPort = _replySlots[i]->_respondToPort;
strlcpy(_respondType, _replySlots[i]->_respondType, sizeof(_respondType));
strlcpy(_usn_suffix, _replySlots[i]->_usn_suffix, sizeof(_usn_suffix));
#ifdef DEBUG_SSDP
DEBUG_SSDP.println("Send None");
#endif
_send(NONE);
sent = true;
delete _replySlots[i];
_replySlots[i] = 0;
}
}
}
#ifdef DEBUG_SSDP
uint8_t rcount = 0;
DEBUG_SSDP.print("SSDP reply queue status: [");
for (int i = 0; i < SSDP_MAX_REPLY_SLOTS; i++) {
DEBUG_SSDP.print(_replySlots[i] ? "X" : "-" );
}
DEBUG_SSDP.println("]");
#endif
if(_notify_time == 0 || (millis() - _notify_time) > (_interval * 1000L)) {
_notify_time = millis();
// send notify with our root device type
strlcpy(_respondType, "upnp:rootdevice", sizeof(_respondType));
strlcpy(_usn_suffix, "::upnp:rootdevice", sizeof(_usn_suffix));
#ifdef DEBUG_SSDP
DEBUG_SSDP.println("Send Notify");
#endif
_send(NOTIFY);
sent = true;
}
if (!sent) {
#ifdef DEBUG_SSDP
DEBUG_SSDP.println("Do not sent");
#endif
} else {
_server->flush();
}
}
void SSDPClass::setSchemaURL(const char *url)
{
strlcpy(_schemaURL, url, sizeof(_schemaURL));
}
void SSDPClass::setHTTPPort(uint16_t port)
{
_port = port;
}
void SSDPClass::setDeviceType(const char *deviceType)
{
strlcpy(_deviceType, deviceType, sizeof(_deviceType));
}
void SSDPClass::setName(const char *name)
{
strlcpy(_friendlyName, name, sizeof(_friendlyName));
}
void SSDPClass::setURL(const char *url)
{
strlcpy(_presentationURL, url, sizeof(_presentationURL));
}
void SSDPClass::setSerialNumber(const char *serialNumber)
{
strlcpy(_serialNumber, serialNumber, sizeof(_serialNumber));
}
void SSDPClass::setSerialNumber(const uint32_t serialNumber)
{
snprintf(_serialNumber, sizeof(uint32_t)*2+1, "%08X", serialNumber);
}
void SSDPClass::setModelName(const char *name)
{
strlcpy(_modelName, name, sizeof(_modelName));
}
void SSDPClass::setModelDescription(const char *desc)
{
_modelDescription = desc;
}
void SSDPClass::setServerName(const char *name)
{
_servername = name;
}
void SSDPClass::setModelNumber(const char *num)
{
strlcpy(_modelNumber, num, sizeof(_modelNumber));
}
void SSDPClass::setModelURL(const char *url)
{
strlcpy(_modelURL, url, sizeof(_modelURL));
}
void SSDPClass::setManufacturer(const char *name)
{
strlcpy(_manufacturer, name, sizeof(_manufacturer));
}
void SSDPClass::setManufacturerURL(const char *url)
{
strlcpy(_manufacturerURL, url, sizeof(_manufacturerURL));
}
void SSDPClass::setTTL(const uint8_t ttl)
{
_ttl = ttl;
}
void SSDPClass::setInterval(uint32_t interval)
{
_interval = interval;
}
void SSDPClass::_onTimerStatic(SSDPClass* self)
{
#ifdef DEBUG_SSDP
DEBUG_SSDP.println("Update");
#endif
self->_update();
}
void SSDPClass::_startTimer()
{
_stopTimer();
_timer= new SSDPTimer();
ETSTimer* tm = &(_timer->timer);
const int interval = 1000;
ets_timer_disarm(tm);
ets_timer_setfn(tm, reinterpret_cast<ETSTimerFunc*>(&SSDPClass::_onTimerStatic), reinterpret_cast<void*>(this));
ets_timer_arm(tm, interval, 1 /* repeat */);
}
void SSDPClass::_stopTimer()
{
if(!_timer) {
return;
}
ETSTimer* tm = &(_timer->timer);
ets_timer_disarm(tm);
delete _timer;
_timer = nullptr;
}
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SSDP)
SSDPClass SSDP;
#endif
#endif

View File

@ -44,18 +44,29 @@ License (MIT license):
#define SSDP_MODEL_VERSION_SIZE 32
#define SSDP_MANUFACTURER_SIZE 64
#define SSDP_MANUFACTURER_URL_SIZE 128
#define SSDP_MAX_REPLY_SLOTS 5
#define SSDP_MAX_DELAY 10000
typedef enum {
NONE,
SEARCH,
NOTIFY
NONE,
SEARCH,
NOTIFY
} ssdp_method_t;
typedef struct {
unsigned long _process_time;
short _delay;
IPAddress _respondToAddr;
uint16_t _respondToPort;
char _respondType[SSDP_DEVICE_TYPE_SIZE];
char _usn_suffix[SSDP_DEVICE_TYPE_SIZE];
} ssdp_reply_slot_item_t;
struct SSDPTimer;
class SSDPClass{
public:
class SSDPClass
{
public:
SSDPClass();
~SSDPClass();
@ -63,53 +74,109 @@ class SSDPClass{
void end();
void schema(WiFiClient client);
const char * schema();
void setDeviceType(const String& deviceType) { setDeviceType(deviceType.c_str()); }
void setDeviceType(const String& deviceType)
{
setDeviceType(deviceType.c_str());
}
void setDeviceType(const char *deviceType);
void setName(const String& name) { setName(name.c_str()); }
void setName(const String& name)
{
setName(name.c_str());
}
void setName(const char *name);
void setURL(const String& url) { setURL(url.c_str()); }
void setURL(const String& url)
{
setURL(url.c_str());
}
void setURL(const char *url);
void setSchemaURL(const String& url) { setSchemaURL(url.c_str()); }
void setSchemaURL(const String& url)
{
setSchemaURL(url.c_str());
}
void setSchemaURL(const char *url);
void setSerialNumber(const String& serialNumber) { setSerialNumber(serialNumber.c_str()); }
void setSerialNumber(const String& serialNumber)
{
setSerialNumber(serialNumber.c_str());
}
void setSerialNumber(const char *serialNumber);
void setSerialNumber(const uint32_t serialNumber);
void setModelName(const String& name) { setModelName(name.c_str()); }
void setModelName(const String& name)
{
setModelName(name.c_str());
}
void setModelName(const char *name);
void setModelNumber(const String& num) { setModelNumber(num.c_str()); }
void setModelNumber(const String& num)
{
setModelNumber(num.c_str());
}
void setModelNumber(const char *num);
void setModelURL(const String& url) { setModelURL(url.c_str()); }
void setModelURL(const String& url)
{
setModelURL(url.c_str());
}
void setModelDescription(const String& desc)
{
setModelDescription(desc.c_str());
}
void setModelDescription(const char *desc);
void setServerName(const String& name)
{
setServerName(name.c_str());
}
void setServerName(const char *name);
void setModelURL(const char *url);
void setManufacturer(const String& name) { setManufacturer(name.c_str()); }
void setManufacturer(const String& name)
{
setManufacturer(name.c_str());
}
void setManufacturer(const char *name);
void setManufacturerURL(const String& url) { setManufacturerURL(url.c_str()); }
void setManufacturerURL(const String& url)
{
setManufacturerURL(url.c_str());
}
void setManufacturerURL(const char *url);
void setHTTPPort(uint16_t port);
void setTTL(uint8_t ttl);
void setInterval(uint32_t interval);
void setUUID(const char * uuid, bool rootonly = true);
void setServices(const char * services)
{
_services = services;
}
void setIcons(const char * icons)
{
_icons = icons;
}
protected:
protected:
void _send(ssdp_method_t method);
void _update();
void _startTimer();
void _stopTimer();
static void _onTimerStatic(SSDPClass* self);
IPAddress localIP();
WiFiUDP *_server;
SSDPTimer* _timer;
WiFiUDP *_server;
SSDPTimer* _timer;
uint16_t _port;
uint8_t _ttl;
uint8_t _interval;
ssdp_reply_slot_item_t *_replySlots[SSDP_MAX_REPLY_SLOTS];
IPAddress _respondToAddr;
uint16_t _respondToPort;
bool _pending;
unsigned short _delay;
bool _stmatch;
short _delay;
unsigned long _process_time;
unsigned long _notify_time;
char _respondType[SSDP_DEVICE_TYPE_SIZE];
char _schemaURL[SSDP_SCHEMA_URL_SIZE];
char _uuid[SSDP_UUID_SIZE];
char _usn_suffix[SSDP_DEVICE_TYPE_SIZE];
char _deviceType[SSDP_DEVICE_TYPE_SIZE];
char _friendlyName[SSDP_FRIENDLY_NAME_SIZE];
char _serialNumber[SSDP_SERIAL_NUMBER_SIZE];
@ -119,6 +186,11 @@ class SSDPClass{
char _modelName[SSDP_MODEL_NAME_SIZE];
char _modelURL[SSDP_MODEL_URL_SIZE];
char _modelNumber[SSDP_MODEL_VERSION_SIZE];
String _modelDescription;
String _servername;
char * _schema;
String _services;
String _icons;
};
#if !defined(NO_GLOBAL_INSTANCES) && !defined(NO_GLOBAL_SSDP)
@ -126,4 +198,4 @@ extern SSDPClass SSDP;
#endif
#endif
#endif
#endif

View File

@ -1,6 +1,10 @@
ESP32 Simple Service Discovery Copyright (c) 2015 Hristo Gochkov
Original (Arduino) version by Filippo Sallemi, July 23, 2014. Can be
found at: https://github.com/nomadnt/uSSDP
found at: https://github.com/nomadnt/uSSDP
[Latest stable release ![Release Version](https://img.shields.io/github/release/luc-github/ESP32SSDP.svg?style=plastic) ![Release Date](https://img.shields.io/github/release-date/luc-github/ESP32SSDP.svg?style=plastic)](https://github.com/luc-github/ESP32SSDP/releases/latest/) [![Travis (.org) branch](https://img.shields.io/travis/luc-github/ESP32SSDP/master?style=plastic)](https://travis-ci.org/luc-github/ESP32SSDP)
[Latest development version ![Development Version](https://img.shields.io/badge/devt-yellow?style=plastic) ![GitHub last commit (branch)](https://img.shields.io/github/last-commit/luc-github/ESP32SSDP/devt?style=plastic)](https://github.com/luc-github/ESP32SSDP/tree/devt) [![Travis (.org) branch](https://img.shields.io/travis/luc-github/ESP32SSDP/devt?style=plastic)](https://travis-ci.org/luc-github/ESP32SSDP)
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the

View File

@ -0,0 +1,19 @@
#!/bin/bash
function build_sketch()
{
local sketch=$1
# buld sketch with arudino ide
echo -e "\n Build $sketch \n"
arduino --verbose --verify $sketch
# get build result from arduino
local re=$?
# check result
if [ $re -ne 0 ]; then
echo "Failed to build $sketch"
return $re
fi
}

View File

@ -0,0 +1,105 @@
#include <WiFi.h>
#include <WebServer.h>
#include <ESP32SSDP.h>
const char* ssid = "********";
const char* password = "********";
WebServer HTTP(80);
void setup()
{
Serial.begin(115200);
Serial.println();
Serial.println("Starting WiFi...");
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
if(WiFi.waitForConnectResult() == WL_CONNECTED) {
Serial.printf("Starting HTTP...\n");
HTTP.on("/index.html", HTTP_GET, []() {
HTTP.send(200, "text/plain", "Hello World!");
});
HTTP.on("/description.xml", HTTP_GET, []() {
SSDP.schema(HTTP.client());
});
HTTP.begin();
//set schema xml url, nees to match http handler
//"ssdp/schema.xml" if not set
SSDP.setSchemaURL("description.xml");
//set port
//80 if not set
SSDP.setHTTPPort(80);
//set device name
//Null string if not set
SSDP.setName("Philips hue clone");
//set Serial Number
//Null string if not set
SSDP.setSerialNumber("001788102201");
//set device url
//Null string if not set
SSDP.setURL("index.html");
//set model name
//Null string if not set
SSDP.setModelName("Philips hue bridge 2012");
//set model description
//Null string if not set
SSDP.setModelDescription("This device can be controled by WiFi");
//set model number
//Null string if not set
SSDP.setModelNumber("929000226503");
//set model url
//Null string if not set
SSDP.setModelURL("http://www.meethue.com");
//set model manufacturer name
//Null string if not set
SSDP.setManufacturer("Royal Philips Electronics");
//set model manufacturer url
//Null string if not set
SSDP.setManufacturerURL("http://www.philips.com");
//set device type
//"urn:schemas-upnp-org:device:Basic:1" if not set
SSDP.setDeviceType("upnp:rootdevice"); //to appear as root device
//set server name
//"Arduino/1.0" if not set
SSDP.setServerName("SSDPServer/1.0");
//set UUID, you can use https://www.uuidgenerator.net/
//use 38323636-4558-4dda-9188-cda0e6 + 4 last bytes of mac address if not set
//use SSDP.setUUID("daa26fa3-d2d4-4072-bc7a-a1b88ab4234a", false); for full UUID
SSDP.setUUID("daa26fa3-d2d4-4072-bc7a");
//Set icons list, NB: optional, this is ignored under windows
SSDP.setIcons( "<icon>"
"<mimetype>image/png</mimetype>"
"<height>48</height>"
"<width>48</width>"
"<depth>24</depth>"
"<url>icon48.png</url>"
"</icon>");
//Set service list, NB: optional for simple device
SSDP.setServices( "<service>"
"<serviceType>urn:schemas-upnp-org:service:SwitchPower:1</serviceType>"
"<serviceId>urn:upnp-org:serviceId:SwitchPower:1</serviceId>"
"<SCPDURL>/SwitchPower1.xml</SCPDURL>"
"<controlURL>/SwitchPower/Control</controlURL>"
"<eventSubURL>/SwitchPower/Event</eventSubURL>"
"</service>");
Serial.printf("Starting SSDP...\n");
SSDP.begin();
Serial.printf("Ready!\n");
} else {
Serial.printf("WiFi Failed\n");
while(1) {
delay(100);
}
}
}
void loop()
{
HTTP.handleClient();
delay(1);
}

View File

@ -1,5 +1,5 @@
name=ESP32SSPD
version=1.0.1
version=1.1.0
author=Me-No-Dev
maintainer=luc-github
sentence=Simple SSDP library for ESP32

View File

@ -0,0 +1,4 @@
cd %~dp0
astyle --recursive --style=otbs *.h *.cpp *.ino
del /S *.ori
pause

View File

@ -0,0 +1,16 @@
#!/bin/bash
#
# $HOME/astyle directory is cached on Travis.
# If cached build is not present, download astyle and build it.
# Install built astyle binary into the home directory.
#
set -e
if [ ! -f $HOME/astyle/build/gcc/bin/astyle ]; then
wget -O astyle_3.1_linux.tar.gz https://sourceforge.net/projects/astyle/files/astyle/astyle%203.1/astyle_3.1_linux.tar.gz/download
tar -xf astyle_3.1_linux.tar.gz -C $HOME
make -C $HOME/astyle/build/gcc
fi
make -C $HOME/astyle/build/gcc prefix=$HOME install

View File

@ -0,0 +1,30 @@
; PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[platformio]
src_dir = .
build_dir = .pioenvs
libdeps_dir = .piolibdeps
lib_dir = ../../..
[env:esp32dev]
platform = https://github.com/platformio/platform-espressif32.git
;theboard
board = esp32dev
framework = arduino
monitor_speed = 115200
; set frequency to 240MHz
board_build.f_cpu = 240000000L
; set frequency to 80MHz
board_build.f_flash = 80000000L
board_build.flash_mode = qio
; No debug
build_flags = -DCORE_DEBUG_LEVEL=0
board_build.partitions = min_spiffs.csv
upload_speed = 921600