-
Notifications
You must be signed in to change notification settings - Fork 48
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
328 additions
and
162 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,104 +1,134 @@ | ||
#pragma once | ||
|
||
#include "ImprovWiFiLibrary.h" | ||
#define HTTP_GET_SIZE 3 | ||
#define HTTP_POST_SIZE 4 | ||
|
||
#include <WiFi.h> | ||
#include <CWPreferences.h> | ||
#include "IOManager.h" | ||
|
||
#include "StatusController.h" | ||
#include "SettingsWebPage.h" | ||
|
||
WiFiServer server(80); | ||
ImprovWiFi improvSerial(&Serial); | ||
|
||
struct ClockwiseWebServer | ||
{ | ||
|
||
char linebuf[80]; | ||
int charcount = 0; | ||
|
||
|
||
static void onImprovWiFiErrorCb(improv::Error err) | ||
String httpBuffer; | ||
|
||
static ClockwiseWebServer *getInstance() | ||
{ | ||
static ClockwiseWebServer base; | ||
return &base; | ||
} | ||
|
||
void startWebServer() | ||
{ | ||
server.begin(); | ||
StatusController::getInstance()->blink_led(100, 3); | ||
} | ||
|
||
void stopWebServer() | ||
{ | ||
server.stop(); | ||
} | ||
|
||
void handleHttpRequest() | ||
{ | ||
WiFiClient client = server.available(); | ||
if (client) | ||
{ | ||
server.stop(); | ||
IOManager::blink_led(2000, 3); | ||
} | ||
|
||
static void onImprovWiFiConnectedCb(std::string ssid, std::string password) | ||
{ | ||
ClockwiseParams::getInstance()->load(); | ||
ClockwiseParams::getInstance()->wifiSsid = String(ssid.c_str()); | ||
ClockwiseParams::getInstance()->wifiPwd = String(password.c_str()); | ||
ClockwiseParams::getInstance()->save(); | ||
|
||
startCWWebServer(); | ||
} | ||
|
||
static void startCWWebServer() { | ||
server.begin(); | ||
IOManager::blink_led(100, 3); | ||
} | ||
StatusController::getInstance()->blink_led(100, 1); | ||
|
||
void begin() | ||
{ | ||
WiFi.mode(WIFI_STA); | ||
WiFi.disconnect(); | ||
|
||
improvSerial.setDeviceInfo(improv::ChipFamily::CF_ESP32, "CW-20230324", "1.1.0", "Clockwise"); | ||
improvSerial.onImprovWiFiError(onImprovWiFiErrorCb); | ||
improvSerial.onImprovWiFiConnected(onImprovWiFiConnectedCb); | ||
|
||
ClockwiseParams::getInstance()->load(); | ||
if (improvSerial.tryConnectToWifi(ClockwiseParams::getInstance()->wifiSsid.c_str(), ClockwiseParams::getInstance()->wifiPwd.c_str())) { | ||
startCWWebServer(); | ||
} | ||
|
||
} | ||
|
||
void handleHttpRequest() | ||
{ | ||
while (client.connected()) | ||
{ | ||
if (client.available()) | ||
{ | ||
char c = client.read(); | ||
httpBuffer.concat(c); | ||
|
||
improvSerial.handleSerial(); | ||
if (c == '\n') | ||
{ | ||
//Serial.println(httpBuffer); | ||
|
||
if (!improvSerial.isConnected()) | ||
return; | ||
uint8_t method_pos = httpBuffer.indexOf(' '); | ||
uint8_t path_pos = httpBuffer.indexOf(' ', method_pos + 1); | ||
|
||
WiFiClient client = server.available(); | ||
String method = httpBuffer.substring(0, method_pos); | ||
String path = httpBuffer.substring(method_pos + 1, path_pos); | ||
String key = ""; | ||
String value = ""; | ||
|
||
if (client) | ||
{ | ||
IOManager::blink_led(100, 1); | ||
memset(linebuf, 0, sizeof(linebuf)); | ||
charcount = 0; | ||
// an http request ends with a blank line | ||
boolean currentLineIsBlank = true; | ||
while (client.connected()) | ||
if (method == "POST") | ||
{ | ||
if (client.available()) | ||
{ | ||
char c = client.read(); | ||
// read char by char HTTP request | ||
linebuf[charcount] = c; | ||
if (charcount < sizeof(linebuf) - 1) | ||
charcount++; | ||
|
||
if (c == '\n' && currentLineIsBlank) | ||
{ | ||
// send a standard http response header | ||
client.println("HTTP/1.1 200 OK"); | ||
client.println("Content-Type: text/html"); | ||
client.println("Connection: close"); // the connection will be closed after completion of the response | ||
client.println(); | ||
client.println("<!DOCTYPE HTML><html><body>"); | ||
client.println("<h1 id=\"welcome\">Welcome!</h1>"); | ||
client.println("<p>This is a simple webpage served by your ESP32</p>"); | ||
client.println("</body></html>"); | ||
break; | ||
} | ||
} | ||
key = path.substring(path.indexOf('?') + 1, path.indexOf('=')); | ||
value = path.substring(path.indexOf('=') + 1, ' '); | ||
path = path.substring(0, path.indexOf('?')); | ||
} | ||
delay(1); | ||
client.stop(); | ||
|
||
processRequest(client, method, path, key, value); | ||
httpBuffer = ""; | ||
break; | ||
} | ||
} | ||
} | ||
delay(1); | ||
client.stop(); | ||
} | ||
} | ||
|
||
void processRequest(WiFiClient client, String method, String path, String key, String value) | ||
{ | ||
|
||
// Serial.println(method); | ||
// Serial.println(path); | ||
// Serial.println(key); | ||
// Serial.println(value); | ||
|
||
if (method == "GET" && path == "/") { | ||
client.println("HTTP/1.0 200 OK"); | ||
client.println("Content-Type: text/html"); | ||
client.println(); | ||
client.println(SETTINGS_PAGE); | ||
} else if (method == "GET" && path == "/get") { | ||
getCurrentSettings(client); | ||
} else if (method == "POST" && path == "/set") { | ||
ClockwiseParams::getInstance()->load(); | ||
|
||
//a baby seal has died due this ifs | ||
if (key == ClockwiseParams::getInstance()->PREF_DISPLAY_BRIGHT) { | ||
ClockwiseParams::getInstance()->displayBright = value.toInt(); | ||
} else if (key == ClockwiseParams::getInstance()->PREF_SWAP_BLUE_GREEN) { | ||
ClockwiseParams::getInstance()->swapBlueGreen = (value == "1"); | ||
} else if (key == ClockwiseParams::getInstance()->PREF_USE_24H_FORMAT) { | ||
ClockwiseParams::getInstance()->use24hFormat = (value == "1"); | ||
} else if (key == ClockwiseParams::getInstance()->PREF_TIME_ZONE) { | ||
ClockwiseParams::getInstance()->timeZone = value; | ||
} | ||
ClockwiseParams::getInstance()->save(); | ||
client.println("HTTP/1.0 204 No Content"); | ||
} | ||
} | ||
|
||
|
||
void getCurrentSettings(WiFiClient client) { | ||
ClockwiseParams::getInstance()->load(); | ||
|
||
char response[256]; | ||
snprintf(response, sizeof(response), "{\"%s\":%d,\"%s\":%d,\"%s\":%d,\"%s\":\"%s\",\"%s\":\"%s\"}", \ | ||
ClockwiseParams::getInstance()->PREF_DISPLAY_BRIGHT, | ||
ClockwiseParams::getInstance()->displayBright, | ||
ClockwiseParams::getInstance()->PREF_SWAP_BLUE_GREEN, | ||
ClockwiseParams::getInstance()->swapBlueGreen, | ||
ClockwiseParams::getInstance()->PREF_USE_24H_FORMAT, | ||
ClockwiseParams::getInstance()->use24hFormat, | ||
ClockwiseParams::getInstance()->PREF_TIME_ZONE, | ||
ClockwiseParams::getInstance()->timeZone.c_str(), | ||
ClockwiseParams::getInstance()->PREF_WIFI_SSID, | ||
ClockwiseParams::getInstance()->wifiSsid.c_str()); | ||
|
||
client.println("HTTP/1.0 200 OK"); | ||
client.println("Content-Type: application/json"); | ||
client.println(); | ||
client.println(response); | ||
} | ||
|
||
|
||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
#pragma once | ||
|
||
#include <Arduino.h> | ||
|
||
|
||
|
||
typedef struct SettingsCards { | ||
const char* title; | ||
const char* description; | ||
const char* formInput; | ||
const char* icon; | ||
const char* propName; | ||
} SettingsCard; | ||
|
||
const char SETTINGS_PAGE[] PROGMEM = R""""( | ||
<!DOCTYPE html> | ||
<html> | ||
<title>Clockwise Settings</title> | ||
<meta name="viewport" content="width=device-width, initial-scale=1"> | ||
<link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css"> | ||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"> | ||
<link rel="shortcut icon" type="image/x-icon" | ||
href="https://github.com/jnthas/clockwise/raw/gh-pages/static/images/favicon.png"> | ||
<body> | ||
<div class="w3-container"> | ||
<img src="https://github.com/jnthas/clockwise/raw/gh-pages/static/images/clockwise_logo.png" alt="Logo" | ||
class="w3-image w3-padding" style="width:50%;max-width:600px"> | ||
</div> | ||
|
||
<div class="w3-panel w3-black"> | ||
<h3>.:: Settings Page</h3> | ||
</div> | ||
<div class="w3-row-padding w3-padding"> | ||
<div id="base" class="w3-col s3 m3 s12" style="display: none;"> | ||
<div class="w3-card-4 w3-margin-bottom"> | ||
<header class="w3-container w3-blue-gray"> | ||
<h3 id="title">{{TITLE}}</h3> | ||
</header> | ||
<div class="w3-container"> | ||
<p style="min-height: 45px;" id="description">{{DESCRIPTION}}</p> | ||
<hr> | ||
<div class="w3-row w3-section"> | ||
<div class="w3-col" style="width:50px"><i id="icon" class="w3-xxlarge w3-text-dark-grey fa"></i></div> | ||
<div class="w3-rest" id="formInput"> | ||
{{FORM_INPUT}} | ||
</div> | ||
</div> | ||
</div> | ||
<button id="cardButton" class="w3-button w3-block w3-light-blue">Save</button> | ||
</div> | ||
</div> | ||
</div> | ||
<script> | ||
function createCards(settings) { | ||
console.log(settings); | ||
const cards = [ | ||
{ | ||
title:"Display Bright", | ||
description:"0 = dark (display off) / 255 = super bright | Value: <strong><output id='rangevalue'>" + settings.displayBright + "</output></strong>", | ||
formInput:"<input class='w3-input w3-border' type='range' min='0' max='255' value='" + settings.displayBright + "' class='slider' id='bright' oninput='rangevalue.value=value'>", | ||
icon:"fa-adjust", | ||
save:"updatePreference('displayBright', bright.value)", | ||
property:"displayBright" | ||
}, | ||
{ | ||
title:"Use 24h format?", | ||
description:"Changes the hour format to show 20:00 instead of 8:00PM", | ||
formInput:"<input class='w3-check' type='checkbox' id='use24h' " + (settings.use24hFormat == 1 ? "checked" : "") + "><label for='use24h'> Yep</label>", | ||
icon:"fa-calendar", | ||
save:"updatePreference('use24hFormat', Number(use24h.checked))", | ||
property:"use24hFormat" | ||
}, | ||
{ | ||
title:"Swap Blue/Green pins?", | ||
description:"Swap Blue and Green pins because the panel is RBG instead of RGB", | ||
formInput:"<input class='w3-check' type='checkbox' id='swapBG' " + (settings.swapBlueGreen == 1 ? "checked" : "") + "><label for='swapBG'> Yep</label>", | ||
icon:"fa-random", | ||
save:"updatePreference('swapBlueGreen', Number(swapBG.checked))", | ||
property:"swapBlueGreen" | ||
}, | ||
{ | ||
title:"Timezone", | ||
description:"Consult your TZ identifier <a href='https://en.wikipedia.org/wiki/List_of_tz_database_time_zones'>here.</a> Examples: America/Sao_Paulo, Europe/Lisbon", | ||
formInput:"<input id='tz' class='w3-input' name='tz' type='text' placeholder='Timezone' value='"+ settings.timeZone +"''>", | ||
icon:"fa-clock-o", | ||
save:"updatePreference('timeZone', tz.value)", | ||
property:"timeZone" | ||
} | ||
]; | ||
|
||
var base = document.querySelector('#base'); | ||
cards.forEach(c => { | ||
|
||
var clone = base.cloneNode(true); | ||
clone.id = c.property; | ||
clone.removeAttribute("style"); | ||
|
||
Array.prototype.slice.call(clone.getElementsByTagName('*')).forEach(e => { | ||
e.id = e.id + "-" + c.property; | ||
}); | ||
|
||
base.before(clone); | ||
document.getElementById("title-" + c.property).innerHTML = c.title | ||
document.getElementById("description-" + c.property).innerHTML = c.description | ||
document.getElementById("formInput-" + c.property).innerHTML = c.formInput | ||
document.getElementById("icon-" + c.property).classList.add(c.icon); | ||
document.getElementById("cardButton-" + c.property).setAttribute("onclick", c.save); | ||
}) | ||
} | ||
|
||
function updatePreference(key, value) { | ||
const xhr = new XMLHttpRequest(); | ||
xhr.open('POST', '/set?' + key + '=' + value); | ||
xhr.send(); | ||
} | ||
|
||
function begin() { | ||
var xmlhttp = new XMLHttpRequest(); | ||
xmlhttp.onreadystatechange = function() { | ||
if (this.readyState == 4 && this.status == 200) { | ||
createCards(JSON.parse(this.responseText)); | ||
} | ||
}; | ||
xmlhttp.open("GET", "/get", true); | ||
xmlhttp.send(); | ||
} | ||
|
||
//Local | ||
//createCards({"displayBright":30,"swapBlueGreen":1,"use24hFormat":0,"timeZone":"Europe/Lisbon","wifiSsid":"test"}); | ||
|
||
//Embedded | ||
begin(); | ||
|
||
</script> | ||
</body> | ||
</html> | ||
)""""; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.