added danjas work
This commit is contained in:
parent
03cb09a693
commit
f7eb6fe9c5
166
works/Danja Vasiliev/otastaImg/DNSServer.cpp
Normal file
166
works/Danja Vasiliev/otastaImg/DNSServer.cpp
Normal file
@ -0,0 +1,166 @@
|
||||
#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();
|
||||
}
|
72
works/Danja Vasiliev/otastaImg/DNSServer.h
Executable file
72
works/Danja Vasiliev/otastaImg/DNSServer.h
Executable file
@ -0,0 +1,72 @@
|
||||
#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
|
||||
|
BIN
works/Danja Vasiliev/otastaImg/data/.DS_Store
vendored
Normal file
BIN
works/Danja Vasiliev/otastaImg/data/.DS_Store
vendored
Normal file
Binary file not shown.
346
works/Danja Vasiliev/otastaImg/data/index.html
Normal file
346
works/Danja Vasiliev/otastaImg/data/index.html
Normal file
@ -0,0 +1,346 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang='en'>
|
||||
<head>
|
||||
<meta charset='utf-8'>
|
||||
<meta name="viewport" content="user-scalable=no" />
|
||||
<link rel='icon' type='image/svg' href='data:null'>
|
||||
<style>
|
||||
|
||||
* {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
body, html {
|
||||
background-color: #000;
|
||||
color: #fff;
|
||||
font-family: monospace;
|
||||
font-size: 200%;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
img, div, canvas {
|
||||
display: block;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100vw;
|
||||
}
|
||||
|
||||
div {
|
||||
display: block;
|
||||
}
|
||||
|
||||
img, canvas {
|
||||
height: 100vw;
|
||||
width: 100vw;
|
||||
/* border: solid 2px red; */
|
||||
}
|
||||
|
||||
img {
|
||||
display: none;
|
||||
}
|
||||
|
||||
div#head, div#game {
|
||||
text-align: center;
|
||||
padding: 0.5em 0 0 0;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 150%;
|
||||
}
|
||||
|
||||
h1.title {
|
||||
font-family: Arial;
|
||||
line-height: 0.9em;
|
||||
text-transform: uppercase;
|
||||
font-size: 350%;
|
||||
font-style: italic;
|
||||
font-weight: bold;
|
||||
margin: 0;
|
||||
padding-top 0.8em;
|
||||
background: -webkit-linear-gradient(#0f0, #f0f);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 110%;
|
||||
margin: 1em;
|
||||
line-height: 1em;
|
||||
}
|
||||
|
||||
div.screen {
|
||||
position: relative;
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
}
|
||||
|
||||
div.screen#intro, div.screen#level1 {
|
||||
background-image: url('scooter-tenor3.gif');
|
||||
background-color: darkorange;
|
||||
background-blend-mode: difference;
|
||||
background-size: cover;
|
||||
transition: all 0.5s cubic-bezier(1,0,1,.50);
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
div.screen#level1 {
|
||||
background-image: url('scooter-fail2.gif');
|
||||
background-color: blue;
|
||||
background-blend-mode: difference;
|
||||
}
|
||||
|
||||
.screen.hide {
|
||||
transform: translate(0,-100vh);
|
||||
position: absolute;
|
||||
background-blend-mode: color-burn !important;
|
||||
}
|
||||
|
||||
div.screen#level1 {
|
||||
z-index:900;
|
||||
|
||||
}
|
||||
|
||||
button.level {
|
||||
background-color: #f00;
|
||||
border: none;
|
||||
color: #fff;
|
||||
padding: 15px 32px;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
font-size: 1.2em;
|
||||
margin: 0.5em 0;
|
||||
width: 100vw;
|
||||
}
|
||||
|
||||
button.off {
|
||||
background-color: #777;
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
button.level i {
|
||||
position: absolute;
|
||||
font-size: 70%;
|
||||
padding-left: 0.4em;
|
||||
}
|
||||
|
||||
button.message {
|
||||
background-color: #fff;
|
||||
border: none;
|
||||
color: #000;
|
||||
padding: 15px 32px;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
font-size: 1.2em;
|
||||
margin: 0.5em 0;
|
||||
width: 50vw;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
canvas#canvas {
|
||||
background-image: url('jump1-640-bg.png');
|
||||
background-size: contain;
|
||||
}
|
||||
|
||||
div#header1 {
|
||||
font-family: Arial;
|
||||
font-size: 200%;
|
||||
font-style: italic;
|
||||
font-weight: bold;
|
||||
margin: 0;
|
||||
margin-bottom: 0.3em;
|
||||
padding-top 0.8em;
|
||||
text-transform: uppercase;
|
||||
background: -webkit-linear-gradient(#0f0, #f0f);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
|
||||
div.stats {
|
||||
margin: 0.3em;
|
||||
color: #000;
|
||||
}
|
||||
|
||||
div.message#nosensors {
|
||||
position: absolute;
|
||||
background-color: black;
|
||||
padding: 0.6em;
|
||||
top: 49%;
|
||||
transform: translateY(-50%);
|
||||
z-index: 2000;
|
||||
display: none;
|
||||
}
|
||||
|
||||
div.message#nosensors.show {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<div id='nosensors' class='message'>
|
||||
<p>Your browser could not connect to phone's sensors.</p>
|
||||
<p>You can try using Firefox browser or continue in finger-action mode!</p>
|
||||
<div><button id='nosensors' class='message'>OKAY</button></div>
|
||||
</div>
|
||||
|
||||
<div id='intro' class='screen'>
|
||||
|
||||
<div id='head' name='head'>
|
||||
<h1 class='title'>NEED 4 SPEED!</h1>
|
||||
<h2>ride or run as fast as possible!</h2>
|
||||
<h2>make sharp turns to bump-up your score!</h2>
|
||||
<h2>receive Uber-l00t for each level you complete!</h2>
|
||||
|
||||
<button id='easy' class='level'>EASY</button>
|
||||
|
||||
<button id='medium' class='level off'>UNEASY <i>Premium</i></button>
|
||||
|
||||
<button id='hard' class='level off'>HARDCORE <i>Premium</i></button>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div id='level1' class='screen'>
|
||||
<div id='game' name='game'>
|
||||
<img id='jump1' name='jump1' src='jump1-640.jpg'>
|
||||
|
||||
<div id='header1' name='header1'>get moving!</div>
|
||||
|
||||
<canvas id='canvas' name='canvas' width='640' height='640'>
|
||||
<span>canvas is not working here</span>
|
||||
</canvas>
|
||||
|
||||
|
||||
<div class='stats'>stamina: <span id='a' name='a'>0</span></div>
|
||||
<div class='stats'>score: <span id='w' name='w'>0</span></div>
|
||||
|
||||
<button id='quit' class='level quit'>QUIT GAME</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
</body>
|
||||
|
||||
<script>
|
||||
|
||||
var intro_screen = document.querySelectorAll('div.screen#intro')[0];
|
||||
var btn_easy = document.querySelectorAll('button#easy')[0];
|
||||
var header1 = document.querySelectorAll('div#header1')[0];
|
||||
|
||||
var msg_nosensors = document.querySelectorAll('div#nosensors')[0];
|
||||
var btn_nosensors = document.querySelectorAll('button#nosensors')[0];
|
||||
|
||||
btn_easy.addEventListener('touchstart', function() {
|
||||
intro_screen.classList.add('hide');
|
||||
});
|
||||
|
||||
btn_nosensors.addEventListener('touchstart', function() {
|
||||
msg_nosensors.remove();
|
||||
});
|
||||
|
||||
|
||||
function addLines(y) {
|
||||
//console.log('run');
|
||||
ctx.drawImage(image, 0, 0, 640, y, 0, 0, 640, y);
|
||||
}
|
||||
|
||||
|
||||
const canvas = document.getElementById('canvas');
|
||||
const ctx = canvas.getContext('2d');
|
||||
const image = document.getElementById('jump1');
|
||||
|
||||
//image.addEventListener('load', e => {
|
||||
//
|
||||
//});
|
||||
|
||||
|
||||
const w_el = document.getElementById('w');
|
||||
const a_el = document.getElementById('a');
|
||||
//const y_el = document.getElementById('y');
|
||||
|
||||
var w = 0;
|
||||
var _y = 0;
|
||||
var _a = 0;
|
||||
|
||||
function gameWon() {
|
||||
header1.innerText = 'YOU WON SOME L00T!';
|
||||
|
||||
setTimeout(function () {
|
||||
window.open('./jump1-p-95.jpg');
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
var do_handles = function(event) {
|
||||
a = Math.round(event.alpha);
|
||||
|
||||
a_el.innerText = a;
|
||||
|
||||
if (a > _a + 10 || a < _a - 1) {
|
||||
w += 1;
|
||||
w_el.innerText = w;
|
||||
progress = Math.round(w/640*100);
|
||||
if (progress > 0) {
|
||||
header1.innerText = progress + '%';
|
||||
}
|
||||
addLines(w);
|
||||
if (progress >= 100) {
|
||||
window.removeEventListener('deviceorientation', do_handles);
|
||||
gameWon();
|
||||
}
|
||||
_a = a;
|
||||
}
|
||||
};
|
||||
|
||||
var th_handles = function(e) {
|
||||
e.preventDefault();
|
||||
y = e.touches[0].clientY;
|
||||
//y_el.innerText = y;
|
||||
|
||||
if (y > _y + 10 || y < _y - 10) {
|
||||
w += 5;
|
||||
w_el.innerText = w;
|
||||
progress = Math.round(w/640*100);
|
||||
if (progress > 0) {
|
||||
header1.innerText = progress + '%';
|
||||
}
|
||||
addLines(w);
|
||||
if (progress >= 100) {
|
||||
document.removeEventListener('touchmove', th_handles);
|
||||
gameWon();
|
||||
}
|
||||
_y = y;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
if(window.DeviceOrientationEvent) {
|
||||
|
||||
window.addEventListener('deviceorientation', do_handles);
|
||||
|
||||
} else {
|
||||
|
||||
msg_nosensors.classList.add('show');
|
||||
header1.innerText='Rub the screen!';
|
||||
|
||||
//console.log('no sensors :(');
|
||||
|
||||
document.addEventListener('touchmove', th_handles);
|
||||
|
||||
}
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
</html>
|
||||
|
BIN
works/Danja Vasiliev/otastaImg/data/jump1-640-bg.png
Normal file
BIN
works/Danja Vasiliev/otastaImg/data/jump1-640-bg.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
BIN
works/Danja Vasiliev/otastaImg/data/jump1-640.jpg
Normal file
BIN
works/Danja Vasiliev/otastaImg/data/jump1-640.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 50 KiB |
BIN
works/Danja Vasiliev/otastaImg/data/jump1-p-95.jpg
Normal file
BIN
works/Danja Vasiliev/otastaImg/data/jump1-p-95.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 904 KiB |
BIN
works/Danja Vasiliev/otastaImg/data/scooter-fail2.gif
Normal file
BIN
works/Danja Vasiliev/otastaImg/data/scooter-fail2.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 202 KiB |
BIN
works/Danja Vasiliev/otastaImg/data/scooter-tenor3.gif
Normal file
BIN
works/Danja Vasiliev/otastaImg/data/scooter-tenor3.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 132 KiB |
98
works/Danja Vasiliev/otastaImg/otastaImg.ino
Normal file
98
works/Danja Vasiliev/otastaImg/otastaImg.ino
Normal file
@ -0,0 +1,98 @@
|
||||
// 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 "need4speed"
|
||||
//#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("opencoil", WiFi.softAPIP());
|
||||
Serial.println("Ready");
|
||||
Serial.print("IP address: ");
|
||||
Serial.println(WiFi.softAPIP());
|
||||
|
||||
//Over-the-Air updates
|
||||
ArduinoOTA.setHostname("opencoil");
|
||||
//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;
|
||||
}
|
@ -3,7 +3,7 @@
|
||||
|
||||
<head>
|
||||
<title>Paracity Gallery v0.41</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=yes"/>
|
||||
<style type="text/css">
|
||||
body {
|
||||
margin: 0;
|
||||
@ -11,7 +11,7 @@
|
||||
width: 100vw;
|
||||
max-height: 100vh;
|
||||
max-width: 100vw;
|
||||
overflow: hidden;
|
||||
overflow: scroll;
|
||||
}
|
||||
|
||||
#paracity a {
|
||||
@ -24,6 +24,7 @@
|
||||
font-size: 10vw;
|
||||
color: #d152b8;
|
||||
text-decoration: none;
|
||||
z-index: 1000;
|
||||
}
|
||||
|
||||
#paracity {
|
||||
@ -124,7 +125,8 @@
|
||||
':`
|
||||
|
||||
</h2>
|
||||
<a href="paracity_gallery_v041.zip">Download</a>
|
||||
<a href="link-to-hotspot-detect.html">CONNECT</a>
|
||||
<a href="paracity_gallery_v041.zip" target="_blank">Download</a>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
||||
//#define STASPSK "mypassword"
|
||||
#endif
|
||||
|
||||
IPAddress apIP(192, 168, 4, 1);
|
||||
IPAddress apIP(8, 8, 8, 8); //changed to google dns to try make it more android friendly?
|
||||
const char* ssid = STASSID;
|
||||
//const char* password = STAPSK;
|
||||
|
||||
@ -43,8 +43,9 @@
|
||||
ArduinoOTA.begin();
|
||||
SPIFFS.begin();
|
||||
|
||||
server.on("/hotspot-detect.html", handleAppleCaptivePortal);//test captive avoid on ios (works!)
|
||||
//redirect all traffic to index.html
|
||||
server.onNotFound([]() {
|
||||
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);
|
||||
@ -81,6 +82,16 @@ String getContentType(String filename){
|
||||
return "text/plain";
|
||||
}
|
||||
|
||||
void handleAppleCaptivePortal() {
|
||||
String Page = F("<HTML><HEAD><TITLE>Success</TITLE></HEAD><BODY>Success</BODY></HTML>");
|
||||
|
||||
server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
|
||||
server.sendHeader("Pragma", "no-cache");
|
||||
server.sendHeader("Expires", "-1");
|
||||
server.send(200, "text/html", Page);
|
||||
return;
|
||||
}
|
||||
|
||||
//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";
|
||||
|
Loading…
Reference in New Issue
Block a user