After Width: | Height: | Size: 399 KiB |
After Width: | Height: | Size: 327 KiB |
After Width: | Height: | Size: 588 KiB |
After Width: | Height: | Size: 643 KiB |
After Width: | Height: | Size: 643 KiB |
After Width: | Height: | Size: 491 KiB |
After Width: | Height: | Size: 507 KiB |
After Width: | Height: | Size: 418 KiB |
After Width: | Height: | Size: 347 KiB |
@ -1,45 +0,0 @@ |
|||||
# opencoil-paracity: code |
|
||||
|
|
||||
### Prerequisites |
|
||||
|
|
||||
This guide assumes you have a 4MB ESP12F microcontroller and use Arduino IDE. |
|
||||
|
|
||||
* Board Manager: You will need to add the support for this board to your IDE (Arduino in this case), see: https://github.com/esp8266/Arduino |
|
||||
* SPIFFS: You will need to add SPIFFS file upload support to Arduino if you want to upload files to the ESP12F, see: https://github.com/esp8266/arduino-esp8266fs-plugin |
|
||||
|
|
||||
|
|
||||
|
|
||||
### Uploading Code |
|
||||
For ESP12F use the following settings in Arduino IDE |
|
||||
|
|
||||
* Board: Generic ESP8266 Module |
|
||||
* Builtin Led: 2 |
|
||||
* Upload Speed: 921600 |
|
||||
* CPU Frequency: 80 MHz |
|
||||
* Crystal Frequency: 26MHz |
|
||||
* Flash Size: 4MB (FS:3MB OTA: ~512KB) |
|
||||
* Flash Mode: DOUT |
|
||||
* Flash Frequency: 40MHz |
|
||||
* Reset Method: dtr (aka nodemcu) |
|
||||
* Debug port: Disabled |
|
||||
* Debug Level: none |
|
||||
* LwIP Variant: v2 Lower Memory |
|
||||
* VTables: Flash |
|
||||
* Exceptions: Legacy (new can return nullptr) |
|
||||
* Erase Flash: depends on if you want to change SSID, Files, or only Sketch |
|
||||
* Espressif FW: nonos-sdk 2.2.1+100 (190703) |
|
||||
* SSL Support: All SSL ciphers (most compatible) |
|
||||
* Port: depend if u are uploading Over The Air, or using a cable |
|
||||
* Programmer: AVRISP mkII |
|
||||
|
|
||||
|
|
||||
These settings give you about 2.471 KB of SPIFFS storage space for files and ~512KB sketch size |
|
||||
|
|
||||
|
|
||||
### Over The Air (OTA) Uploading |
|
||||
|
|
||||
* Connect to the hotspot created by the ESP12F. |
|
||||
* Launch Arduino, choose "esp at 192.168.4.1" as the port. |
|
||||
* If you don't see the port listed in Arduino (Tools > Port), restart Arduino IDE. |
|
||||
|
|
||||
You can upload your sketch and files wirelessly, there is one caveat: SPIFFS file uploads don't work with password protected uploads (line 42). Workaround: flash your sketch with line 42 commented out. Upload your files to SPIFFS, then uncomment the line and Upload the code. |
|
@ -1,166 +0,0 @@ |
|||||
#include "./DNSServer.h" |
|
||||
#include <lwip/def.h> |
|
||||
#include <Arduino.h> |
|
||||
|
|
||||
#define DEBUG |
|
||||
#define DEBUG_OUTPUT Serial |
|
||||
|
|
||||
DNSServer::DNSServer() |
|
||||
{ |
|
||||
_ttl = htonl(60); |
|
||||
_errorReplyCode = DNSReplyCode::NonExistentDomain; |
|
||||
} |
|
||||
|
|
||||
bool DNSServer::start(const uint16_t &port, const String &domainName, |
|
||||
const IPAddress &resolvedIP) |
|
||||
{ |
|
||||
_port = port; |
|
||||
_domainName = domainName; |
|
||||
_resolvedIP[0] = resolvedIP[0]; |
|
||||
_resolvedIP[1] = resolvedIP[1]; |
|
||||
_resolvedIP[2] = resolvedIP[2]; |
|
||||
_resolvedIP[3] = resolvedIP[3]; |
|
||||
downcaseAndRemoveWwwPrefix(_domainName); |
|
||||
return _udp.begin(_port) == 1; |
|
||||
} |
|
||||
|
|
||||
void DNSServer::setErrorReplyCode(const DNSReplyCode &replyCode) |
|
||||
{ |
|
||||
_errorReplyCode = replyCode; |
|
||||
} |
|
||||
|
|
||||
void DNSServer::setTTL(const uint32_t &ttl) |
|
||||
{ |
|
||||
_ttl = htonl(ttl); |
|
||||
} |
|
||||
|
|
||||
void DNSServer::stop() |
|
||||
{ |
|
||||
_udp.stop(); |
|
||||
} |
|
||||
|
|
||||
void DNSServer::downcaseAndRemoveWwwPrefix(String &domainName) |
|
||||
{ |
|
||||
domainName.toLowerCase(); |
|
||||
domainName.replace("www.", ""); |
|
||||
domainName.replace("https://", ""); |
|
||||
} |
|
||||
|
|
||||
void DNSServer::processNextRequest() |
|
||||
{ |
|
||||
_currentPacketSize = _udp.parsePacket(); |
|
||||
if (_currentPacketSize) |
|
||||
{ |
|
||||
_buffer = (unsigned char*)malloc(_currentPacketSize * sizeof(char)); |
|
||||
_udp.read(_buffer, _currentPacketSize); |
|
||||
_dnsHeader = (DNSHeader*) _buffer; |
|
||||
|
|
||||
if (_dnsHeader->QR == DNS_QR_QUERY && |
|
||||
_dnsHeader->OPCode == DNS_OPCODE_QUERY && |
|
||||
requestIncludesOnlyOneQuestion() && |
|
||||
(_domainName == "*" || getDomainNameWithoutWwwPrefix() == _domainName) |
|
||||
) |
|
||||
|
|
||||
{ |
|
||||
replyWithIP(); |
|
||||
} |
|
||||
else if (_dnsHeader->QR == DNS_QR_QUERY) |
|
||||
{ |
|
||||
replyWithCustomCode(); |
|
||||
} |
|
||||
|
|
||||
free(_buffer); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
bool DNSServer::requestIncludesOnlyOneQuestion() |
|
||||
{ |
|
||||
return ntohs(_dnsHeader->QDCount) == 1 && |
|
||||
_dnsHeader->ANCount == 0 && |
|
||||
_dnsHeader->NSCount == 0 && |
|
||||
_dnsHeader->ARCount == 0; |
|
||||
} |
|
||||
|
|
||||
String DNSServer::getDomainNameWithoutWwwPrefix() |
|
||||
{ |
|
||||
String parsedDomainName = ""; |
|
||||
unsigned char *start = _buffer + 12; |
|
||||
if (*start == 0) |
|
||||
{ |
|
||||
return parsedDomainName; |
|
||||
} |
|
||||
int pos = 0; |
|
||||
while(true) |
|
||||
{ |
|
||||
unsigned char labelLength = *(start + pos); |
|
||||
for(int i = 0; i < labelLength; i++) |
|
||||
{ |
|
||||
pos++; |
|
||||
parsedDomainName += (char)*(start + pos); |
|
||||
} |
|
||||
pos++; |
|
||||
if (*(start + pos) == 0) |
|
||||
{ |
|
||||
downcaseAndRemoveWwwPrefix(parsedDomainName); |
|
||||
return parsedDomainName; |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
parsedDomainName += "."; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
void DNSServer::replyWithIP() |
|
||||
{ |
|
||||
_dnsHeader->QR = DNS_QR_RESPONSE; |
|
||||
_dnsHeader->ANCount = _dnsHeader->QDCount; |
|
||||
_dnsHeader->QDCount = _dnsHeader->QDCount; |
|
||||
//_dnsHeader->RA = 1;
|
|
||||
|
|
||||
_udp.beginPacket(_udp.remoteIP(), _udp.remotePort()); |
|
||||
_udp.write(_buffer, _currentPacketSize); |
|
||||
|
|
||||
_udp.write((uint8_t)192); // answer name is a pointer
|
|
||||
_udp.write((uint8_t)12); // pointer to offset at 0x00c
|
|
||||
|
|
||||
_udp.write((uint8_t)0); // 0x0001 answer is type A query (host address)
|
|
||||
_udp.write((uint8_t)1); |
|
||||
|
|
||||
_udp.write((uint8_t)0); //0x0001 answer is class IN (internet address)
|
|
||||
_udp.write((uint8_t)1); |
|
||||
|
|
||||
_udp.write((unsigned char*)&_ttl, 4); |
|
||||
|
|
||||
// Length of RData is 4 bytes (because, in this case, RData is IPv4)
|
|
||||
_udp.write((uint8_t)0); |
|
||||
_udp.write((uint8_t)4); |
|
||||
_udp.write(_resolvedIP, sizeof(_resolvedIP)); |
|
||||
_udp.endPacket(); |
|
||||
|
|
||||
|
|
||||
|
|
||||
#ifdef DEBUG |
|
||||
DEBUG_OUTPUT.print("DNS responds: "); |
|
||||
DEBUG_OUTPUT.print(_resolvedIP[0]); |
|
||||
DEBUG_OUTPUT.print("."); |
|
||||
DEBUG_OUTPUT.print(_resolvedIP[1]); |
|
||||
DEBUG_OUTPUT.print("."); |
|
||||
DEBUG_OUTPUT.print(_resolvedIP[2]); |
|
||||
DEBUG_OUTPUT.print("."); |
|
||||
DEBUG_OUTPUT.print(_resolvedIP[3]); |
|
||||
DEBUG_OUTPUT.print(" for "); |
|
||||
DEBUG_OUTPUT.println(getDomainNameWithoutWwwPrefix()); |
|
||||
#endif |
|
||||
} |
|
||||
|
|
||||
void DNSServer::replyWithCustomCode() |
|
||||
{ |
|
||||
_dnsHeader->QR = DNS_QR_RESPONSE; |
|
||||
_dnsHeader->RCode = (unsigned char)_errorReplyCode; |
|
||||
_dnsHeader->QDCount = 0; |
|
||||
|
|
||||
_udp.beginPacket(_udp.remoteIP(), _udp.remotePort()); |
|
||||
_udp.write(_buffer, sizeof(DNSHeader)); |
|
||||
_udp.endPacket(); |
|
||||
} |
|
@ -1,72 +0,0 @@ |
|||||
#ifndef DNSServer_h |
|
||||
#define DNSServer_h |
|
||||
#include <WiFiUdp.h> |
|
||||
|
|
||||
#define DNS_QR_QUERY 0 |
|
||||
#define DNS_QR_RESPONSE 1 |
|
||||
#define DNS_OPCODE_QUERY 0 |
|
||||
|
|
||||
enum class DNSReplyCode |
|
||||
{ |
|
||||
NoError = 0, |
|
||||
FormError = 1, |
|
||||
ServerFailure = 2, |
|
||||
NonExistentDomain = 3, |
|
||||
NotImplemented = 4, |
|
||||
Refused = 5, |
|
||||
YXDomain = 6, |
|
||||
YXRRSet = 7, |
|
||||
NXRRSet = 8 |
|
||||
}; |
|
||||
|
|
||||
struct DNSHeader |
|
||||
{ |
|
||||
uint16_t ID; // identification number
|
|
||||
unsigned char RD : 1; // recursion desired
|
|
||||
unsigned char TC : 1; // truncated message
|
|
||||
unsigned char AA : 1; // authoritive answer
|
|
||||
unsigned char OPCode : 4; // message_type
|
|
||||
unsigned char QR : 1; // query/response flag
|
|
||||
unsigned char RCode : 4; // response code
|
|
||||
unsigned char Z : 3; // its z! reserved
|
|
||||
unsigned char RA : 1; // recursion available
|
|
||||
uint16_t QDCount; // number of question entries
|
|
||||
uint16_t ANCount; // number of answer entries
|
|
||||
uint16_t NSCount; // number of authority entries
|
|
||||
uint16_t ARCount; // number of resource entries
|
|
||||
}; |
|
||||
|
|
||||
class DNSServer |
|
||||
{ |
|
||||
public: |
|
||||
DNSServer(); |
|
||||
void processNextRequest(); |
|
||||
void setErrorReplyCode(const DNSReplyCode &replyCode); |
|
||||
void setTTL(const uint32_t &ttl); |
|
||||
|
|
||||
// Returns true if successful, false if there are no sockets available
|
|
||||
bool start(const uint16_t &port, |
|
||||
const String &domainName, |
|
||||
const IPAddress &resolvedIP); |
|
||||
// stops the DNS server
|
|
||||
void stop(); |
|
||||
|
|
||||
private: |
|
||||
WiFiUDP _udp; |
|
||||
uint16_t _port; |
|
||||
String _domainName; |
|
||||
unsigned char _resolvedIP[4]; |
|
||||
int _currentPacketSize; |
|
||||
unsigned char* _buffer; |
|
||||
DNSHeader* _dnsHeader; |
|
||||
uint32_t _ttl; |
|
||||
DNSReplyCode _errorReplyCode; |
|
||||
|
|
||||
void downcaseAndRemoveWwwPrefix(String &domainName); |
|
||||
String getDomainNameWithoutWwwPrefix(); |
|
||||
bool requestIncludesOnlyOneQuestion(); |
|
||||
void replyWithIP(); |
|
||||
void replyWithCustomCode(); |
|
||||
}; |
|
||||
#endif |
|
||||
|
|
@ -1,12 +0,0 @@ |
|||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> |
|
||||
<html> |
|
||||
|
|
||||
<head> |
|
||||
<title></title> |
|
||||
</head> |
|
||||
<body> |
|
||||
|
|
||||
hi |
|
||||
<img src="pic.jpg"> |
|
||||
</body> |
|
||||
</html> |
|
Before Width: | Height: | Size: 108 KiB |
@ -1,98 +0,0 @@ |
|||||
// Captive portal with (arduino) OTA + SPIFFS
|
|
||||
|
|
||||
#include <Arduino.h> |
|
||||
#include <ESP8266WiFi.h> |
|
||||
#include <ESP8266mDNS.h> |
|
||||
#include <WiFiUdp.h> |
|
||||
#include <ArduinoOTA.h> // Over-the-Air updates |
|
||||
#include <ESP8266WebServer.h> |
|
||||
#include "./DNSServer.h" // Dns server |
|
||||
#include <FS.h> // SPIFFS |
|
||||
|
|
||||
DNSServer dnsServer; |
|
||||
const byte DNS_PORT = 53; |
|
||||
|
|
||||
ESP8266WebServer server(80); |
|
||||
|
|
||||
#ifndef STASSID |
|
||||
#define STASSID "\xF0\x9F\x9B\xB4 UNFLASHED" |
|
||||
//#define STASPSK "mypassword"
|
|
||||
#endif |
|
||||
|
|
||||
IPAddress apIP(192, 168, 4, 1); |
|
||||
const char* ssid = STASSID; |
|
||||
//const char* password = STAPSK;
|
|
||||
|
|
||||
void setup() { |
|
||||
Serial.begin(115200); |
|
||||
Serial.println("Booting"); |
|
||||
|
|
||||
WiFi.mode(WIFI_AP); |
|
||||
WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0)); |
|
||||
WiFi.softAP(ssid); |
|
||||
dnsServer.start(DNS_PORT, "*", apIP); // redirect dns request to AP ip
|
|
||||
|
|
||||
MDNS.begin("esp8266", WiFi.softAPIP()); |
|
||||
Serial.println("Ready"); |
|
||||
Serial.print("IP address: "); |
|
||||
Serial.println(WiFi.softAPIP()); |
|
||||
|
|
||||
//Over-the-Air updates
|
|
||||
ArduinoOTA.setHostname("ESP8266"); |
|
||||
//ArduinoOTA.setPassword("change-me"); //disabled to allow data uploads
|
|
||||
ArduinoOTA.begin(); |
|
||||
SPIFFS.begin(); |
|
||||
|
|
||||
//redirect all traffic to index.html
|
|
||||
server.onNotFound([]() { |
|
||||
if(!handleFileRead(server.uri())){ |
|
||||
const char *metaRefreshStr = "<head><meta http-equiv=\"refresh\" content=\"0; url=http://192.168.4.1/index.html\" /></head><body><p>redirecting...</p></body>"; |
|
||||
server.send(200, "text/html", metaRefreshStr); |
|
||||
} |
|
||||
}); |
|
||||
|
|
||||
server.begin(); |
|
||||
|
|
||||
} |
|
||||
|
|
||||
void loop() { |
|
||||
dnsServer.processNextRequest(); |
|
||||
ArduinoOTA.handle(); |
|
||||
server.handleClient(); |
|
||||
delay(50); |
|
||||
} |
|
||||
|
|
||||
|
|
||||
String getContentType(String filename){ |
|
||||
if(server.hasArg("download")) return "application/octet-stream"; |
|
||||
else if(filename.endsWith(".htm")) return "text/html"; |
|
||||
else if(filename.endsWith(".html")) return "text/html"; |
|
||||
else if(filename.endsWith(".css")) return "text/css"; |
|
||||
else if(filename.endsWith(".js")) return "application/javascript"; |
|
||||
else if(filename.endsWith(".png")) return "image/png"; |
|
||||
else if(filename.endsWith(".gif")) return "image/gif"; |
|
||||
else if(filename.endsWith(".jpg")) return "image/jpeg"; |
|
||||
else if(filename.endsWith(".ico")) return "image/x-icon"; |
|
||||
else if(filename.endsWith(".xml")) return "text/xml"; |
|
||||
else if(filename.endsWith(".mp4")) return "video/mp4"; |
|
||||
else if(filename.endsWith(".pdf")) return "application/x-pdf"; |
|
||||
else if(filename.endsWith(".zip")) return "application/x-zip"; |
|
||||
else if(filename.endsWith(".gz")) return "application/x-gzip"; |
|
||||
return "text/plain"; |
|
||||
} |
|
||||
|
|
||||
//Given a file path, look for it in the SPIFFS file storage. Returns true if found, returns false if not found.
|
|
||||
bool handleFileRead(String path){ |
|
||||
if(path.endsWith("/")) path += "index.html"; |
|
||||
String contentType = getContentType(path); |
|
||||
String pathWithGz = path + ".gz"; |
|
||||
if(SPIFFS.exists(pathWithGz) || SPIFFS.exists(path)){ |
|
||||
if(SPIFFS.exists(pathWithGz)) |
|
||||
path += ".gz"; |
|
||||
File file = SPIFFS.open(path, "r"); |
|
||||
size_t sent = server.streamFile(file, contentType); |
|
||||
file.close(); |
|
||||
return true; |
|
||||
} |
|
||||
return false; |
|
||||
} |
|