-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
remove upload_port = /dev/ttyUSB0 from ini file
- Loading branch information
Showing
9 changed files
with
662 additions
and
60 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 |
---|---|---|
|
@@ -10,4 +10,5 @@ compile_commands.json | |
__pycache__ | ||
.DS_Store | ||
.vscode | ||
src/www/build | ||
.vscode/* |
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,93 @@ | ||
#!/usr/bin/env python3 | ||
# | ||
# This script converts standard web content files (html, css, etc) into a C++ language | ||
# header file that is included in the program body. The files are compressed and use | ||
# PROGMEM keyword to store in Flash to save RAM. | ||
# Requires: gzip, xxd and sed. | ||
# | ||
# Copyright (c) 2023 David Kerr, https://github.com/dkerr64 | ||
# | ||
import os | ||
import subprocess | ||
import shutil | ||
|
||
sourcepath = "src/www" | ||
targetpath = sourcepath + "/build" | ||
|
||
filenames = next(os.walk(sourcepath), (None, None, []))[2] | ||
print("Compressing and converting files from " + sourcepath + " into " + targetpath) | ||
print(filenames) | ||
|
||
# Start by deleting the target directory, then creating empty one. | ||
try: | ||
shutil.rmtree(targetpath) | ||
except FileNotFoundError: | ||
pass | ||
os.mkdir(targetpath) | ||
|
||
# Open webcontent file and write warning header... | ||
wf = open(targetpath + "/webcontent.h", "w") | ||
wf.write("/**************************************\n") | ||
wf.write(" * Autogenerated DO NOT EDIT\n") | ||
wf.write(" **************************************/\n") | ||
wf.write("#include \"Arduino.h\"\n") | ||
wf.write("#include <string>\n") | ||
wf.flush() | ||
|
||
varnames = [] | ||
# now loop through each file... | ||
for file in filenames: | ||
gzfile = targetpath + "/" + file + ".gz" | ||
varnames.append(("/" + file, gzfile.replace(".", "_").replace("/", "_"))) | ||
f = open(gzfile, "w") | ||
subprocess.run(["gzip", "-c", sourcepath + "/" + file], stdout=f) | ||
f.close() | ||
subprocess.run(["xxd", "-i", gzfile], stdout=wf) | ||
|
||
wf.flush() | ||
|
||
# Add possible MIME types to the file... | ||
wf.write( | ||
""" | ||
char type_svg[] = "image/svg+xml"; | ||
char type_bmp[] = "image/bmp"; | ||
char type_gif[] = "image/gif"; | ||
char type_jpeg[] = "image/jpeg"; | ||
char type_jpg[] = "image/jpeg"; | ||
char type_png[] = "image/png"; | ||
char type_tiff[] = "image/tiff"; | ||
char type_tif[] = "image/tiff"; | ||
char type_txt[] = "text/plain"; | ||
char type_htm[] = "text/html"; | ||
char type_html[] = "text/html"; | ||
char type_css[] = "text/css"; | ||
char type_js[] = "text/javascript"; | ||
char type_mjs[] = "text/javascript"; | ||
char type_json[] = "application/json"; | ||
""" | ||
) | ||
|
||
# Use an unordered_map so we can lookup the data, length and type based on filename... | ||
wf.write( | ||
"std::unordered_map<std::string, std::tuple<unsigned char *, unsigned int, char *>> webcontent = {" | ||
) | ||
n = 0 | ||
for file, var in varnames: | ||
t = file.rpartition(".")[-1] | ||
# Need comma at end of every line except last one... | ||
if n > 0: | ||
wf.write(",") | ||
wf.write('\n { "' + file + '", {' + var + ", " + var + "_len, type_" + t + "} }") | ||
n = n + 1 | ||
|
||
# All done, close the file... | ||
wf.write("\n};\n") | ||
wf.close() | ||
|
||
# Add the PROGMEM keyword to tell system to leave contents in Flash and not load into RAM... | ||
subprocess.run( | ||
["sed", "-i", "s/_gz\[\]/_gz\[\] PROGMEM/g", targetpath + "/webcontent.h"] | ||
) | ||
|
||
print("processed " + str(len(varnames)) + " files") |
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
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,105 +1,212 @@ | ||
// Copyright 2023 Brandon Matthews <thenewwazoo@optimaltour.us> | ||
// Copyright (c) 2023-24 David Kerr, https://github.com/dkerr64 | ||
// All rights reserved. GPLv3 License | ||
|
||
#include "www/build/webcontent.h" | ||
|
||
#include <arduino_homekit_server.h> | ||
#include <ESP8266WebServer.h> | ||
#include <ESP8266HTTPUpdateServer.h> | ||
#include "log.h" | ||
#include "ratgdo.h" | ||
|
||
#include <ESP8266WebServer.h> | ||
#include <ESP8266HTTPUpdateServer.h> | ||
|
||
ESP8266WebServer server(80); | ||
ESP8266HTTPUpdateServer httpUpdater(true); | ||
|
||
/********* forward decl *********/ | ||
|
||
void handle_root(); | ||
void handle_reset(); | ||
void handle_reboot(); | ||
void handle_notfound(); | ||
void handle_handlestatus(); | ||
|
||
extern struct GarageDoor garage_door; | ||
|
||
// Make device_name available | ||
extern "C" char device_name[]; | ||
|
||
/********* main loop **********/ | ||
|
||
void setup_web() { | ||
server.on("/", HTTP_GET, handle_root); | ||
void setup_web() | ||
{ | ||
server.on("/status.json", HTTP_GET, handle_handlestatus); | ||
server.on("/reset", HTTP_POST, handle_reset); | ||
server.on("/reboot", HTTP_POST, handle_reboot); | ||
|
||
server.onNotFound([]() { | ||
server.send(404, "text/plain", "404: Not Found"); | ||
}); | ||
|
||
server.onNotFound(handle_notfound); | ||
|
||
httpUpdater.setup(&server); | ||
|
||
server.begin(); | ||
RINFO("HTTP server started"); | ||
} | ||
|
||
void web_loop() { | ||
void web_loop() | ||
{ | ||
server.handleClient(); | ||
} | ||
|
||
/********* handlers **********/ | ||
|
||
void handle_root() { | ||
if (homekit_is_paired()) { | ||
server.send( | ||
200, | ||
"text/html", | ||
"<p>If you wish to re-pair to another HomeKit Home, you must first click the following button:</p>" | ||
"<form action=\"/reset\" method=\"POST\">" | ||
"<input type=\"submit\" value=\"Un-pair HomeKit\">" | ||
"</form>" | ||
"<p>To reboot the RATGDO, click the following button:</p>" | ||
"<form action=\"/reboot\" method=\"POST\">" | ||
"<input type=\"submit\" value=\"Reboot RATGDO\">" | ||
"</form>" | ||
"<p>Current Firmware Version: v" AUTO_VERSION "</p>" | ||
"<form action=\"/update\">" | ||
"<input type=\"submit\" value=\"Update Firmware\">" | ||
"</form>"); | ||
} else { | ||
server.send( | ||
200, | ||
"text/html", | ||
"<p>Scan the following QR code with your iOS device to pair with HomeKit:</p>" | ||
#include "qrcode.h" | ||
"<p>If you wish to re-pair to another HomeKit Home, you must first click the following button:</p>" | ||
"<form action=\"/reset\" method=\"POST\">" | ||
"<input type=\"submit\" value=\"Un-pair HomeKit\">" | ||
"</form>" | ||
"<p>To reboot the RATGDO, click the following button:</p>" | ||
"<form action=\"/reboot\" method=\"POST\">" | ||
"<input type=\"submit\" value=\"Reboot RATGDO\">" | ||
"</form>" | ||
"<p>Current Firmware Version: v" AUTO_VERSION "</p>" | ||
"<form action=\"/update\">" | ||
"<input type=\"submit\" value=\"Update Firmware\">" | ||
"</form>"); | ||
} | ||
} | ||
|
||
void handle_reset() { | ||
void handle_reset() | ||
{ | ||
RINFO("... reset requested"); | ||
homekit_storage_reset(); | ||
|
||
server.send( | ||
200, | ||
"text/html", | ||
"<p>This device has been un-paired from HomeKit.</p>" | ||
"<p><a href=\"/\">Back</a></p>" | ||
); | ||
"<p><a href=\"/\">Back</a></p>"); | ||
} | ||
|
||
void handle_reboot() { | ||
void handle_reboot() | ||
{ | ||
RINFO("... reboot requested"); | ||
server.send( | ||
200, | ||
"text/html", | ||
"<head>" | ||
"<meta http-equiv=\"refresh\" content=\"15;url=/\" />" | ||
"<meta http-equiv=\"refresh\" content=\"15;url=/\" />" | ||
"</head>" | ||
"<body>" | ||
"<p>RATGDO restarting. Please wait. Reconnecting in 15 seconds...</p>" | ||
"<p><a href=\"/\">Back</a></p>" | ||
"</body>" | ||
); | ||
server.stop(); // ensure that delivery is complete? | ||
delay(10); // give a bit of time for the connection to close fully | ||
"<p>RATGDO restarting. Please wait. Reconnecting in 15 seconds...</p>" | ||
"<p><a href=\"/\">Back</a></p>" | ||
"</body>"); | ||
|
||
server.stop(); | ||
delay(10); // give a bit of time for the connection to close fully | ||
ESP.restart(); | ||
} | ||
|
||
void handle_notfound() | ||
{ | ||
String page = server.uri(); | ||
|
||
if (page == "/") | ||
{ | ||
page = "/index.html"; | ||
} | ||
|
||
if (webcontent.count(page.c_str()) > 0) | ||
{ | ||
unsigned char *data; | ||
unsigned int length; | ||
char *type; | ||
std::tie(data, length, type) = webcontent[page.c_str()]; | ||
RINFO("Sending gzip data for: %s (type %s, length %i)", page.c_str(), type, length); | ||
server.sendHeader("Content-Encoding", "gzip"); | ||
server.send_P(200, type, (const char *)data, length); | ||
} | ||
else | ||
{ | ||
RINFO("Sending 404 not found for: %s", page.c_str()); | ||
server.send(404, "text/plain", "404: Not Found"); | ||
} | ||
return; | ||
} | ||
|
||
void handle_handlestatus() | ||
{ | ||
homekit_server_t *hks = arduino_homekit_get_running_server(); | ||
|
||
// If arguments passed with the URL then only a subset of the | ||
// status fields are requested... | ||
std::unordered_map<std::string, bool> argReq; | ||
bool all = true; | ||
if (server.args() > 0) | ||
{ | ||
all = false; | ||
for (int i = 0; i < server.args(); i++) | ||
{ | ||
argReq[server.argName(i).c_str()] = true; | ||
} | ||
} | ||
|
||
// Build the JSON string | ||
// Note that newlines and indentation are not required within the json, | ||
// but are included to improve readability in the console log. | ||
std::string json = "{\n"; // open the json | ||
if (all || argReq["uptime"]) | ||
json.append(std::string(" \"upTime\": ") + std::to_string(millis()) + ",\n"); | ||
if (all) | ||
json.append(std::string(" \"deviceName\": \"") + device_name + "\",\n"); | ||
if (all) | ||
json.append(std::string(" \"paired\": ") + (homekit_is_paired() ? "true" : "false") + ",\n"); | ||
if (all) | ||
json.append(std::string(" \"firmwareVersion\": \"") + std::string(AUTO_VERSION) + "\",\n"); | ||
if (all) | ||
json.append(std::string(" \"accessoryID\": \"") + hks->accessory_id + "\",\n"); | ||
if (all) | ||
json.append(std::string(" \"localIP\": \"") + WiFi.localIP().toString().c_str() + "\",\n"); | ||
if (all) | ||
json.append(std::string(" \"subnetMask\": \"") + WiFi.subnetMask().toString().c_str() + "\",\n"); | ||
if (all) | ||
json.append(std::string(" \"gatewayIP\": \"") + WiFi.gatewayIP().toString().c_str() + "\",\n"); | ||
if (all) | ||
json.append(std::string(" \"macAddress\": \"") + WiFi.macAddress().c_str() + "\",\n"); | ||
if (all) | ||
json.append(std::string(" \"wifiSSID\": \"") + WiFi.SSID().c_str() + "\",\n"); | ||
if (all || argReq["doorstate"]) | ||
{ | ||
std::string doorState = ""; | ||
switch (garage_door.current_state) | ||
{ | ||
case 0: | ||
doorState = "Open"; | ||
break; | ||
case 1: | ||
doorState = "Closed"; | ||
break; | ||
case 2: | ||
doorState = "Opening"; | ||
break; | ||
case 3: | ||
doorState = "Closing"; | ||
break; | ||
case 4: | ||
doorState = "Stopped"; | ||
break; | ||
default: | ||
doorState = "Unknown"; | ||
} | ||
json.append(std::string(" \"garageDoorState\": \"") + doorState + "\",\n"); | ||
} | ||
if (all || argReq["lockstate"]) | ||
{ | ||
std::string lockState = ""; | ||
switch (garage_door.current_lock) | ||
{ | ||
case 0: | ||
lockState = "Unsecured"; | ||
break; | ||
case 1: | ||
lockState = "Secured"; | ||
break; | ||
case 2: | ||
lockState = "Jammed"; | ||
break; | ||
default: | ||
lockState = "Unknown"; | ||
} | ||
json.append(std::string(" \"garageLockState\": \"") + lockState + "\",\n"); | ||
} | ||
if (all || argReq["lighton"]) | ||
json.append(std::string(" \"garageLightOn\": ") + (garage_door.light ? "true" : "false") + ",\n"); | ||
if (all || argReq["motion"]) | ||
json.append(std::string(" \"garageMotion\": ") + (garage_door.motion ? "true" : "false") + ",\n"); | ||
if (all || argReq["obstruction"]) | ||
json.append(std::string(" \"garageObstructed\": ") + (garage_door.obstructed ? "true" : "false") + ",\n"); | ||
|
||
// remove the final comma/newline to ensure valid JSON syntax | ||
json.erase(json.rfind(",\n")); | ||
json.append("\n}"); // close the json | ||
|
||
// Only log if all requested (no arguments). | ||
// Avoids spaming console log if repeated requests for one value. | ||
if (all) | ||
RINFO("Status requested:\n%s", json.c_str()); | ||
|
||
server.send(200, "application/json", json.c_str()); | ||
return; | ||
} |
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.