added auto-incrementing build number to the Makefile (available as "esp_link_build" in the C code)

converted the unconditional downloading of YUI compressor and HTML compressor to be conditional - only if they are not already present
moved all Javascript blocks from HTML files into separate JS files - otherwise HTML compressor does not compress the inlined Javascript code
changed the place of inclusion of JS files into HTML - it is now at the end of BODY instead of beginning (this speeds up the page loading a little)
added a page "Firmware" which allows for OTA upgrades - so the utility "wiflash" is no more needed
improved the Makefile to show firmware size as a percentage of the available ROM space
improved the Makefile to show the espFS size as a percentage of the raw uncompressed size of web assets
combined the 2 invokations of HTML compressor in Makefile (once for main folder and once for WIFI folder) into a single one
changed 4-5 CSS rules for better visual readability
fixed a bug in "cgiGetFirmwareNext" - it was not sending the No-Cache headers and so the browser shows wrong (older, cached) info
added "\n" in several DBG() statements
I had to rename "base64_decode" because there is same named function inside "ssl_crypto_misc" from the SSL library
pull/173/head
tmcdos 8 years ago
parent 65534229f2
commit 95d7e8e391
  1. 107
      Makefile
  2. 6
      esp-link/cgi.c
  3. 6
      esp-link/cgiflash.c
  4. 4
      esp-link/cgiwifi.c
  5. 22
      esp-link/main.c
  6. 81
      html/console.html
  7. 264
      html/home.html
  8. 50
      html/log.html
  9. 18
      html/mqtt.html
  10. 6
      html/mqtt.js
  11. 4
      html/pure.css
  12. 203
      html/services.html
  13. 7
      html/services.js
  14. 73
      html/style.css
  15. 18
      html/ui.js
  16. 143
      html/wifi/wifiAp.html
  17. 27
      html/wifi/wifiAp.js
  18. 89
      html/wifi/wifiSta.html
  19. 9
      html/wifi/wifiSta.js
  20. 4
      httpd/auth.c
  21. 2
      httpd/base64.c
  22. 2
      httpd/base64.h
  23. 2
      httpd/httpd.c
  24. 5
      include/user_config.h

@ -84,7 +84,7 @@ ESPBAUD ?= 460800
# --------------- chipset configuration ---------------
# Pick your flash size: "512KB", "1MB", or "4MB"
# Pick your flash size: "512KB", "1MB", "2MB" or "4MB"
FLASH_SIZE ?= 4MB
# The pin assignments below are used when the settings in flash are invalid, they
@ -135,13 +135,12 @@ YUI_COMPRESSOR ?= yuicompressor-2.4.8.jar
HTML_PATH = $(abspath ./html)/
WIFI_PATH = $(HTML_PATH)wifi/
ESP_FLASH_MAX ?= 503808 # max bin file
ifeq ("$(FLASH_SIZE)","512KB")
# Winbond 25Q40 512KB flash, typ for esp-01 thru esp-11
ESP_SPI_SIZE ?= 0 # 0->512KB (256KB+256KB)
ESP_FLASH_MODE ?= 0 # 0->QIO
ESP_FLASH_FREQ_DIV ?= 0 # 0->40Mhz
ESP_FLASH_MAX ?= 241664 # max bin file for 512KB flash: 236KB
ET_FS ?= 4m # 4Mbit flash size in esptool flash command
ET_FF ?= 40m # 40Mhz flash speed in esptool flash command
ET_BLANK ?= 0x7E000 # where to flash blank.bin to erase wireless settings
@ -151,6 +150,7 @@ else ifeq ("$(FLASH_SIZE)","1MB")
ESP_SPI_SIZE ?= 2 # 2->1MB (512KB+512KB)
ESP_FLASH_MODE ?= 0 # 0->QIO
ESP_FLASH_FREQ_DIV ?= 15 # 15->80MHz
ESP_FLASH_MAX ?= 503808 # max bin file for 1MB flash: 492KB
ET_FS ?= 8m # 8Mbit flash size in esptool flash command
ET_FF ?= 80m # 80Mhz flash speed in esptool flash command
ET_BLANK ?= 0xFE000 # where to flash blank.bin to erase wireless settings
@ -163,6 +163,7 @@ else ifeq ("$(FLASH_SIZE)","2MB")
ESP_SPI_SIZE ?= 4 # 6->4MB (1MB+1MB) or 4->4MB (512KB+512KB)
ESP_FLASH_MODE ?= 0 # 0->QIO, 2->DIO
ESP_FLASH_FREQ_DIV ?= 15 # 15->80Mhz
ESP_FLASH_MAX ?= 503808 # max bin file for 2MB flash: 492KB
ET_FS ?= 16m # 16Mbit flash size in esptool flash command
ET_FF ?= 80m # 80Mhz flash speed in esptool flash command
ET_BLANK ?= 0x1FE000 # where to flash blank.bin to erase wireless settings
@ -175,6 +176,8 @@ else
ESP_SPI_SIZE ?= 4 # 6->4MB (1MB+1MB) or 4->4MB (512KB+512KB)
ESP_FLASH_MODE ?= 0 # 0->QIO, 2->DIO
ESP_FLASH_FREQ_DIV ?= 15 # 15->80Mhz
ESP_FLASH_MAX ?= 503808 # max bin file for 512KB flash partition: 492KB
#ESP_FLASH_MAX ?= 1028096 # max bin file for 1MB flash partition: 1004KB
ET_FS ?= 32m # 32Mbit flash size in esptool flash command
ET_FF ?= 80m # 80Mhz flash speed in esptool flash command
ET_BLANK ?= 0x3FE000 # where to flash blank.bin to erase wireless settings
@ -187,12 +190,17 @@ endif
# Steps to release: create release on github, git pull, git describe --tags to verify you're
# on the release tag, make release, upload esp-link.tgz into the release files
#VERSION ?= "esp-link custom version"
DATE := $(shell date '+%F %T')
DATE := $(shell date '+%F')
TIME := $(shell date '+%T')
BRANCH ?= $(shell if git diff --quiet HEAD; then git describe --tags; \
else git symbolic-ref --short HEAD; fi)
SHA := $(shell if git diff --quiet HEAD; then git rev-parse --short HEAD | cut -d"/" -f 3; \
else echo "development"; fi)
VERSION ?=esp-link $(BRANCH) - $(DATE) - $(SHA)
VERSION ?=esp-link $(BRANCH) - $(DATE) - $(TIME) - $(SHA)
BUILD_NUMBER_FILE = $(abspath ./build-number.txt)
BUILD_NUMBER_SRC = $(abspath ./user/buildnum.c)
BUILD_NUMBER := $(shell if ! test -f $(BUILD_NUMBER_FILE); then echo 1 > $(BUILD_NUMBER_FILE); fi; cat $(BUILD_NUMBER_FILE))
# Output directors to store intermediate compiled files
# relative to the project directory
@ -227,15 +235,15 @@ MODULES += $(foreach sdir,$(LIBRARIES_DIR),$(wildcard $(sdir)/*))
EXTRA_INCDIR = include .
# libraries used in this project, mainly provided by the SDK
LIBS = c gcc hal phy pp net80211 wpa main lwip crypto
LIBS = c gcc hal phy pp net80211 wpa main lwip crypto ssl
# compiler flags using during compilation of source files
CFLAGS += -Os -ggdb -std=c99 -Werror -Wpointer-arith -Wundef -Wall -Wl,-EL -fno-inline-functions \
CFLAGS += -Os -ggdb -std=c99 -Werror -Wno-unused-value -Wpointer-arith -Wundef -Wall -Wl,-EL -fno-inline-functions \
-nostdlib -mlongcalls -mtext-section-literals -ffunction-sections -fdata-sections \
-D__ets__ -DICACHE_FLASH -Wno-address -DFIRMWARE_SIZE=$(ESP_FLASH_MAX) \
-DMCU_RESET_PIN=$(MCU_RESET_PIN) -DMCU_ISP_PIN=$(MCU_ISP_PIN) \
-DLED_CONN_PIN=$(LED_CONN_PIN) -DLED_SERIAL_PIN=$(LED_SERIAL_PIN) \
-DVERSION="$(VERSION)"
-DVERSION="$(VERSION)" -DBUILD_DATE="$(DATE)" -DBUILD_TIME="$(TIME)" -DBUILD_NUM="$(BUILD_NUMBER)"
# linker flags used to generate the main object file
LDFLAGS = -nostdlib -Wl,--no-check-sections -u call_user_start -Wl,-static -Wl,--gc-sections
@ -343,13 +351,23 @@ all: echo_version checkdirs $(FW_BASE)/user1.bin $(FW_BASE)/user2.bin
echo_version:
@echo VERSION: $(VERSION)
# Create an auto-incrementing build number.
@echo "#define VER_STR2(V) #V" > $(BUILD_NUMBER_SRC)
@echo "#define VER_STR(V) VER_STR2(V)" >> $(BUILD_NUMBER_SRC)
@echo "char esp_link_version[] = VER_STR(VERSION);" >> $(BUILD_NUMBER_SRC)
@echo "char esp_link_date[] = VER_STR(BUILD_DATE);" >> $(BUILD_NUMBER_SRC)
@echo "char esp_link_time[] = VER_STR(BUILD_TIME);" >> $(BUILD_NUMBER_SRC)
@echo "char esp_link_build[] = VER_STR(BUILD_NUM);" >> $(BUILD_NUMBER_SRC)
# Build number file. Increment if firmware file changes
$(BUILD_NUMBER_FILE): $(USER1_OUT)
@if ! test -f $(BUILD_NUMBER_FILE); then echo 0 > $(BUILD_NUMBER_FILE); fi
@echo $$(($$(cat $(BUILD_NUMBER_FILE)) + 1)) > $(BUILD_NUMBER_FILE)
$(USER1_OUT): $(APP_AR) $(LD_SCRIPT1)
$(vecho) "LD $@"
$(Q) $(LD) -L$(SDK_LIBDIR) -T$(LD_SCRIPT1) $(LDFLAGS) -Wl,--start-group $(LIBS) $(APP_AR) -Wl,--end-group -o $@
@echo Dump : $(OBJDP) -x $(USER1_OUT)
@echo Disass: $(OBJDP) -d -l -x $(USER1_OUT)
# $(Q) $(OBJDP) -x $(TARGET_OUT) | egrep espfs_img
$(Q) $(OBJDP) -S $(USER1_OUT) > $(addprefix $(BUILD_BASE)/,$(TARGET).dump)
$(USER2_OUT): $(APP_AR) $(LD_SCRIPT2)
$(vecho) "LD $@"
@ -360,16 +378,15 @@ $(FW_BASE):
$(vecho) "FW $@"
$(Q) mkdir -p $@
$(FW_BASE)/user1.bin: $(USER1_OUT) $(FW_BASE)
$(FW_BASE)/user1.bin: $(USER1_OUT) $(FW_BASE) $(BUILD_NUMBER_FILE)
$(Q) $(OBJCP) --only-section .text -O binary $(USER1_OUT) eagle.app.v6.text.bin
$(Q) $(OBJCP) --only-section .data -O binary $(USER1_OUT) eagle.app.v6.data.bin
$(Q) $(OBJCP) --only-section .rodata -O binary $(USER1_OUT) eagle.app.v6.rodata.bin
$(Q) $(OBJCP) --only-section .irom0.text -O binary $(USER1_OUT) eagle.app.v6.irom0text.bin
ls -ls eagle*bin
$(Q) COMPILE=gcc PATH=$(XTENSA_TOOLS_ROOT):$(PATH) python $(APPGEN_TOOL) $(USER1_OUT) 2 $(ESP_FLASH_MODE) $(ESP_FLASH_FREQ_DIV) $(ESP_SPI_SIZE) 0
$(Q) rm -f eagle.app.v6.*.bin
$(Q) mv eagle.app.flash.bin $@
@echo "** user1.bin uses $$(stat -c '%s' $@) bytes of" $(ESP_FLASH_MAX) "available"
@echo "** user1.bin uses $$(stat -c '%s' $@) bytes of" $(ESP_FLASH_MAX) "available =" $(shell expr $$(stat -c '%s' $@) \* 100 / $(ESP_FLASH_MAX) ) "%"
$(Q) if [ $$(stat -c '%s' $@) -gt $$(( $(ESP_FLASH_MAX) )) ]; then echo "$@ too big!"; false; fi
$(FW_BASE)/user2.bin: $(USER2_OUT) $(FW_BASE)
@ -410,60 +427,55 @@ tools/$(HTML_COMPRESSOR):
else
tools/$(HTML_COMPRESSOR):
$(Q) mkdir -p tools
cd tools; wget https://github.com/yui/yuicompressor/releases/download/v2.4.8/$(YUI_COMPRESSOR)
cd tools; wget https://htmlcompressor.googlecode.com/files/$(HTML_COMPRESSOR)
$(Q) if ! test -f tools/$(YUI_COMPRESSOR); then wget https://github.com/yui/yuicompressor/releases/download/v2.4.8/$(YUI_COMPRESSOR) -O tools/$(YUI_COMPRESSOR); fi
$(Q) if ! test -f tools/$(HTML_COMPRESSOR); then wget https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/htmlcompressor/$(HTML_COMPRESSOR) -O tools/$(HTML_COMPRESSOR); fi
endif
ifeq ("$(COMPRESS_W_HTMLCOMPRESSOR)","yes")
$(BUILD_BASE)/espfs_img.o: tools/$(HTML_COMPRESSOR)
endif
$(BUILD_BASE)/espfs_img.o: html/ html/wifi/ espfs/mkespfsimage/mkespfsimage
$(Q) rm -rf html_compressed; mkdir html_compressed; mkdir html_compressed/wifi;
$(Q) cp -r html/*.ico html_compressed;
$(Q) cp -r html/*.css html_compressed;
$(Q) cp -r html/*.js html_compressed;
$(Q) cp -r html/wifi/*.png html_compressed/wifi;
$(Q) cp -r html/wifi/*.js html_compressed/wifi;
$(BUILD_BASE)/espfs_img.o: $(shell find html) espfs/mkespfsimage/mkespfsimage
$(Q) rm -rf html_compressed; mkdir -p html_compressed; cp -r html/* html_compressed;
ifeq ("$(COMPRESS_W_HTMLCOMPRESSOR)","yes")
$(Q) echo "Compression assets with htmlcompressor. This may take a while..."
$(Q) java -jar tools/$(HTML_COMPRESSOR) \
-t html --remove-surrounding-spaces max --remove-quotes --remove-intertag-spaces \
-o $(abspath ./html_compressed)/ \
$(HTML_PATH)head- \
$(HTML_PATH)*.html
$(Q) java -jar tools/$(HTML_COMPRESSOR) \
-t html --remove-surrounding-spaces max --remove-quotes --remove-intertag-spaces \
-o $(abspath ./html_compressed)/wifi/ \
$(WIFI_PATH)*.html
$(Q) echo "Compression assets with yui-compressor. This may take a while..."
$(Q) echo "Compression assets with htmlcompressor. This is fast..."
$(Q) for file in `find html_compressed -type f -name "*.html"`; do \
java -jar yui/$(HTML_COMPRESSOR) \
-t html --remove-surrounding-spaces max --remove-quotes --remove-intertag-spaces \
-o $$file $$file; \
done
$(Q) echo "Compressing JS/CSS with yui-compressor. This may take a while..."
$(Q) for file in `find html_compressed -type f -name "*.js"`; do \
java -jar tools/$(YUI_COMPRESSOR) $$file --line-break 0 -o $$file; \
java -jar yui/$(YUI_COMPRESSOR) $$file --line-break 0 -o $$file; \
done
$(Q) for file in `find html_compressed -type f -name "*.css"`; do \
java -jar tools/$(YUI_COMPRESSOR) $$file -o $$file; \
java -jar yui/$(YUI_COMPRESSOR) $$file -o $$file; \
done
else
$(Q) cp -r html/head- html_compressed;
$(Q) cp -r html/*.html html_compressed;
$(Q) cp -r html/wifi/*.html html_compressed/wifi;
endif
ifeq (,$(findstring mqtt,$(MODULES)))
$(Q) rm -rf html_compressed/mqtt.html
$(Q) rm -rf html_compressed/mqtt.js
endif
$(Q) for file in `find html_compressed -type f -name "*.htm*"`; do \
cat html_compressed/head- $$file >$${file}-; \
mv $$file- $$file; \
done
$(Q) rm html_compressed/head-
$(Q) echo "Now building espFS ..."
$(Q) cd html_compressed; find . \! -name \*- | ../espfs/mkespfsimage/mkespfsimage > ../build/espfs.img; cd ..;
$(Q) ls -sl build/espfs.img
@echo "espFS image is $$(stat -c '%s' build/espfs.img) bytes =" $(shell expr $$(stat -c '%s' build/espfs.img) \* 100 / $$(du -sb html_compressed | { read first _ ; echo $$first; })) "% of uncompressed originals"
$(Q) cd build; $(OBJCP) -I binary -O elf32-xtensa-le -B xtensa --rename-section .data=.espfs \
espfs.img espfs_img.o; cd ..
# edit the loader script to add the espfs section to the end of irom with a 4 byte alignment.
# we also adjust the sizes of the segments 'cause we need more irom0
# in the end the only thing that matters wrt size is that the whole shebang fits into the
# 236KB available (in a 512KB flash)
ifeq ("$(FLASH_SIZE)","512KB")
build/eagle.esphttpd1.v6.ld: $(SDK_LDDIR)/eagle.app.v6.new.512.app1.ld
$(Q) sed -e '/\.irom\.text/{' -e 'a . = ALIGN (4);' -e 'a *(.espfs)' -e '}' \
-e '/^ irom0_0_seg/ s/2B000/38000/' \
$(SDK_LDDIR)/eagle.app.v6.new.512.app1.ld >$@
build/eagle.esphttpd2.v6.ld: $(SDK_LDDIR)/eagle.app.v6.new.512.app2.ld
$(Q) sed -e '/\.irom\.text/{' -e 'a . = ALIGN (4);' -e 'a *(.espfs)' -e '}' \
-e '/^ irom0_0_seg/ s/2B000/38000/' \
$(SDK_LDDIR)/eagle.app.v6.new.512.app2.ld >$@
else
build/eagle.esphttpd1.v6.ld: $(SDK_LDDIR)/eagle.app.v6.new.1024.app1.ld
$(Q) sed -e '/\.irom\.text/{' -e 'a . = ALIGN (4);' -e 'a *(.espfs)' -e '}' \
-e '/^ irom0_0_seg/ s/6B000/7C000/' \
@ -472,8 +484,9 @@ build/eagle.esphttpd2.v6.ld: $(SDK_LDDIR)/eagle.app.v6.new.1024.app2.ld
$(Q) sed -e '/\.irom\.text/{' -e 'a . = ALIGN (4);' -e 'a *(.espfs)' -e '}' \
-e '/^ irom0_0_seg/ s/6B000/7C000/' \
$(SDK_LDDIR)/eagle.app.v6.new.1024.app2.ld >$@
endif
espfs/mkespfsimage/mkespfsimage: espfs/mkespfsimage/
espfs/mkespfsimage/mkespfsimage: espfs/mkespfsimage/*.c
$(Q) $(MAKE) -C espfs/mkespfsimage GZIP_COMPRESSION="$(GZIP_COMPRESSION)"
release: all

@ -27,10 +27,11 @@ void ICACHE_FLASH_ATTR noCacheHeaders(HttpdConnData *connData, int code) {
httpdStartResponse(connData, code);
httpdHeader(connData, "Cache-Control", "no-cache, no-store, must-revalidate");
httpdHeader(connData, "Pragma", "no-cache");
httpdHeader(connData, "Expires", "0");
httpdHeader(connData, "Expires", "Mon, 26 Jul 1997 05:00:00 GMT");
}
void ICACHE_FLASH_ATTR jsonHeader(HttpdConnData *connData, int code) {
httpdStartResponse(connData, code);
noCacheHeaders(connData, code);
httpdHeader(connData, "Content-Type", "application/json");
httpdEndHeaders(connData);
@ -187,8 +188,6 @@ int ICACHE_FLASH_ATTR printGlobalInfo(char *buff, int buflen, char *token) {
}
#endif
extern char *esp_link_version; // in user_main.c
int ICACHE_FLASH_ATTR cgiMenu(HttpdConnData *connData) {
if (connData->conn==NULL) return HTTPD_CGI_DONE; // Connection aborted. Clean up.
char buff[1024];
@ -214,6 +213,7 @@ int ICACHE_FLASH_ATTR cgiMenu(HttpdConnData *connData) {
"\"REST/MQTT\", \"/mqtt.html\", "
#endif
"\"Debug log\", \"/log.html\""
"\"Firmware\", \"/flash/flash.html\""
" ], "
"\"version\": \"%s\", "
"\"name\": \"%s\""

@ -57,11 +57,11 @@ int ICACHE_FLASH_ATTR cgiGetFirmwareNext(HttpdConnData *connData) {
}
uint8 id = system_upgrade_userbin_check();
httpdStartResponse(connData, 200);
noCacheHeaders(connData, 200);
httpdHeader(connData, "Content-Type", "text/plain");
httpdHeader(connData, "Content-Length", "9");
httpdEndHeaders(connData);
char *next = id == 1 ? "user1.bin" : "user2.bin";
char *next = (id == 1 ? "user1.bin" : "user2.bin");
httpdSend(connData, next, -1);
DBG("Next firmware: %s (got %d)\n", next, id);
return HTTPD_CGI_DONE;
@ -124,7 +124,7 @@ int ICACHE_FLASH_ATTR cgiUploadFirmware(HttpdConnData *connData) {
// erase next flash block if necessary
if (address % SPI_FLASH_SEC_SIZE == 0){
DBG("Flashing 0x%05x (id=%d)\n", address, 2 - id);
DBG("Flashing 0x%05X (id=%d)\n", address, 2 - id);
spi_flash_erase_sector(address/SPI_FLASH_SEC_SIZE);
}

@ -732,8 +732,8 @@ int ICACHE_FLASH_ATTR printWifiInfo(char *buff) {
if (rssi > 0) rssi = 0;
uint8 mac_addr[6];
uint8 apmac_addr[6];
wifi_get_macaddr(0, mac_addr);
wifi_get_macaddr(1, apmac_addr);
wifi_get_macaddr(STATION_IF, mac_addr);
wifi_get_macaddr(SOFTAP_IF, apmac_addr);
uint8_t chan = wifi_get_channel();
len = os_sprintf(buff,

@ -64,6 +64,8 @@ should be placed above the URLs they protect.
HttpdBuiltInUrl builtInUrls[] = {
{ "/", cgiRedirect, "/home.html" },
{ "/menu", cgiMenu, NULL },
{"/flash", cgiRedirect, "/flash/flash.html"},
{"/flash/", cgiRedirect, "/flash/flash.html"},
{ "/flash/next", cgiGetFirmwareNext, NULL },
{ "/flash/upload", cgiUploadFirmware, NULL },
{ "/flash/reboot", cgiRebootFirmware, NULL },
@ -107,10 +109,6 @@ static void ICACHE_FLASH_ATTR prHeapTimerCb(void *arg) {
}
#endif
# define VERS_STR_STR(V) #V
# define VERS_STR(V) VERS_STR_STR(V)
char* esp_link_version = VERS_STR(VERSION);
// address of espfs binary blob
extern uint32_t _binary_espfs_img_start;
@ -139,7 +137,7 @@ void user_init(void) {
logInit(); // must come after init of uart
// Say hello (leave some time to cause break in TX after boot loader's msg
os_delay_us(10000L);
os_printf("\n\n** %s\n", esp_link_version);
os_printf("\n\n** %s, build %s\n", esp_link_version, esp_link_build);
os_printf("Flash config restore %s\n", restoreOk ? "ok" : "*FAILED*");
// Status LEDs
statusInit();
@ -162,26 +160,26 @@ void user_init(void) {
#endif
struct rst_info *rst_info = system_get_rst_info();
NOTICE("Reset cause: %d=%s", rst_info->reason, rst_codes[rst_info->reason]);
NOTICE("exccause=%d epc1=0x%x epc2=0x%x epc3=0x%x excvaddr=0x%x depc=0x%x",
NOTICE("Reset cause: %d=%s\n", rst_info->reason, rst_codes[rst_info->reason]);
NOTICE("exccause=%d epc1=0x%x epc2=0x%x epc3=0x%x excvaddr=0x%x depc=0x%x\n",
rst_info->exccause, rst_info->epc1, rst_info->epc2, rst_info->epc3,
rst_info->excvaddr, rst_info->depc);
uint32_t fid = spi_flash_get_id();
NOTICE("Flash map %s, manuf 0x%02X chip 0x%04X", flash_maps[system_get_flash_size_map()],
NOTICE("Flash map %s, manuf 0x%02X chip 0x%04X\n", flash_maps[system_get_flash_size_map()],
fid & 0xff, (fid&0xff00)|((fid>>16)&0xff));
NOTICE("** %s: ready, heap=%ld", esp_link_version, (unsigned long)system_get_free_heap_size());
NOTICE("** %s: ready, heap=%ld\n", esp_link_version, (unsigned long)system_get_free_heap_size());
// Init SNTP service
cgiServicesSNTPInit();
#ifdef MQTT
if (flashConfig.mqtt_enable) {
NOTICE("initializing MQTT");
NOTICE("initializing MQTT\n");
mqtt_client_init();
}
#endif
NOTICE("initializing user application");
NOTICE("initializing user application\n");
app_init();
NOTICE("Waiting for work to do...");
NOTICE("Waiting for work to do...\n");
#ifdef MEMLEAK_DEBUG
system_show_malloc();
#endif

@ -1,25 +1,38 @@
<!doctype html>
<html><head>
<title>esp-link</title>
<link rel="stylesheet" href="pure.css">
<link rel="stylesheet" href="style.css">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<div id="layout">
<div id="main" class="flex-fill flex-vbox" style="max-height:100%">
<div class="header">
<h1>Microcontroller Console</h1>
</div>
<div class="content flex-fill flex-vbox">
<p>
<p>The Microcontroller console shows the last 1024 characters
received from UART0, to which a microcontroller is typically attached.
The UART is configured for 8 bits, no parity, 1 stop bit (8N1).
</p>
<div>
<a id="reset-button" class="pure-button button-primary" href="#">Reset &#xb5;C</a>
&nbsp; <a id="clear-button" class="pure-button button-primary" href="#">Clear Log</a>
&nbsp; Baud:
&nbsp; Baud (8N1):
<select id="baud-sel" class="pure-button" href="#">
<option value="460800">460800</option>
<option value="250000">250000</option>
<option value="230400">230400</option>
<option value="115200">115200</option>
<option value="57600">57600</option>
<option value="38400">38400</option>
<option value="19200">19200</option>
<option value="0"> </option>
<option value="9600">9600</option>
<option value="19200">19200</option>
<option value="38400">38400</option>
<option value="57600">57600</option>
<option value="115200">115200</option>
<option value="230400">230400</option>
<option value="250000">250000</option>
<option value="460800">460800</option>
</select>
&nbsp; Fmt: 8N1
</p>
</div>
<div class="pure-g">
<div class="pure-u-1-4"><legend><b>Console</b></legend></div>
<div class="pure-u-3-4"></div>
@ -56,49 +69,7 @@
</div>
</div>
</div>
<script type="text/javascript">console_url = "/console/text"</script>
<script src="ui.js"></script>
<script src="console.js"></script>
<script type="text/javascript">
onLoad(function() {
fetchText(100, true);
$("#reset-button").addEventListener("click", function(e) {
e.preventDefault();
var co = $("#console");
co.innerHTML = "";
ajaxSpin('POST', "/console/reset",
function(resp) { showNotification("uC reset"); co.textEnd = 0; },
function(s, st) { showWarning("Error resetting uC"); }
);
});
$("#clear-button").addEventListener("click", function(e) {
e.preventDefault();
var co = $("#console");
co.innerHTML = "";
});
ajaxJson('GET', "/console/baud",
function(data) { $("#baud-sel").value = data.rate; },
function(s, st) { showNotification(st); }
);
bnd($("#baud-sel"), "change", function(ev) {
ev.preventDefault();
var baud = $("#baud-sel").value;
ajaxSpin('POST', "/console/baud?rate="+baud,
function(resp) { showNotification("" + baud + " baud set"); },
function(s, st) { showWarning("Error setting baud rate: " + st); }
);
});
consoleSendInit();
addClass($('html')[0], "height100");
addClass($('body')[0], "height100");
addClass($('#layout'), "height100");
addClass($('#layout'), "flex-vbox");
});
</script>
<script src="console_main.js"></script>
</body></html>

@ -1,3 +1,12 @@
<!doctype html>
<html><head>
<title>esp-link</title>
<link rel="stylesheet" href="pure.css">
<link rel="stylesheet" href="style.css">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<div id="layout">
<div id="main">
<div class="header">
<div><img src="favicon.ico" height="64"><span class="jl">JEELABS</span></div>
@ -6,150 +15,137 @@
</div>
<div class="content">
<div class="pure-g">
<!-- LEFT COLUMN -->
<div class="pure-u-1 pure-u-md-1-2">
<div class="card">
<h1>System overview</h1>
<div id="wifi-spinner" class="spinner spinner-small"></div>
<table id="wifi-table" class="pure-table pure-table-horizontal" hidden><tbody>
<tr><td class="popup-target">Hostname</td><td>
<div class="click-to-edit system-name">
<span class="edit-off"></span>
<input class="edit-on" maxlength=31 hidden></input>
<div class="popup">Click to edit!<br>Hostname displayed in menu bar
and used by DHCP and mDNS</div>
</div>
</td></tr>
<tr><td>Network SSID</td><td id="wifi-ssid"></td></tr>
<tr><td>WiFi status</td><td id="wifi-status"></td></tr>
<tr><td>WiFi address</td><td id="wifi-ip"></td></tr>
<tr><td>SLIP status</td><td class="system-slip"></td></tr>
<tr><td>MQTT status</td><td class="system-mqtt"></td></tr>
<tr><td>Serial baud</td><td class="system-baud"></td></tr>
</tbody></table>
</div>
<div class="card">
<h1>Info</h1>
<p style="margin-bottom:0;">The JeeLabs esp-link firmware bridges the ESP8266
serial port to WiFi and can
program microcontrollers over the serial port, in particular Arduinos, AVRs, and
NXP's LPC800 and other ARM processors. Typical avrdude command line to
program an Arduino:</p>
<div class="tt" style="font-size:100%;">
/home/arduino/hardware/tools/avrdude&nbsp;\<br>
&nbsp;&nbsp;-DV -patmega328p \<br>
&nbsp;&nbsp;-Pnet:esp-link.local:23 \<br>
&nbsp;&nbsp;-carduino -b115200 \<br>
&nbsp;&nbsp;-U flash:w:my_sketch.hex:i\<br>
&nbsp;&nbsp;-C /home/arduino/hardware/tools/avrdude.conf
</div>
<p>where <tt>-Pnet:esp-link.local:23</tt> tells avrdude to connect to port 23 of esp-link.
You can substitute the IP address of your esp-link for esp-link.local if necessary.
Please refer to
<a href="https://github.com/jeelabs/esp-link/blob/master/README.md">the online README</a>
for up-to-date help.</p>
<div style="float:left; padding:2px">
<div class="card">
<h1>System overview</h1>
<div id="wifi-spinner" class="spinner spinner-small"></div>
<table id="wifi-table" class="pure-table pure-table-horizontal" hidden><tbody>
<tr><td class="popup-target">Hostname</td><td>
<div class="click-to-edit system-name">
<span class="edit-off"></span>
<input class="edit-on" maxlength=31 hidden></input>
<div class="popup">Click to edit!<br>Hostname displayed in menu bar
and used by DHCP and mDNS</div>
</div>
</td></tr>
<tr><td>Network SSID</td><td id="wifi-ssid"></td></tr>
<tr><td>WiFi status</td><td id="wifi-status"></td></tr>
<tr><td>WiFi address</td><td id="wifi-ip"></td></tr>
<tr><td>SLIP status</td><td class="system-slip"></td></tr>
<tr><td>MQTT status</td><td class="system-mqtt"></td></tr>
<tr><td>Serial baud</td><td class="system-baud"></td></tr>
</tbody></table>
</div>
<div class="card">
<h1>Info</h1>
<p style="margin-bottom:0;">The JeeLabs esp-link firmware bridges the ESP8266
serial port to WiFi and can
program microcontrollers over the serial port, in particular Arduinos, AVRs, and
NXP's LPC800 and other ARM processors. Typical avrdude command line to
program an Arduino:</p>
<div class="tt" style="font-size:100%;">
/home/arduino/hardware/tools/avrdude&nbsp;\<br>
&nbsp;&nbsp;-DV -patmega328p \<br>
&nbsp;&nbsp;-Pnet:esp-link.local:23 \<br>
&nbsp;&nbsp;-carduino -b115200 \<br>
&nbsp;&nbsp;-U flash:w:my_sketch.hex:i\<br>
&nbsp;&nbsp;-C /home/arduino/hardware/tools/avrdude.conf
</div>
<p>where <tt>-Pnet:esp-link.local:23</tt> tells avrdude to connect to port 23 of esp-link.
You can substitute the IP address of your esp-link for esp-link.local if necessary.
Please refer to
<a href="https://github.com/jeelabs/esp-link/blob/master/README.md">the online README</a>
for up-to-date help.</p>
</div>
<!-- RIGHT COLUMN -->
<div class="pure-u-1 pure-u-md-1-2">
<div class="card">
<h1>Pin assignment</h1>
<div id="pin-spinner" class="spinner spinner-small"></div>
<div id="pin-table" hidden>
<form action="#" id="pinform" class="pure-form pure-form-aligned form-narrow">
<div class="pure-control-group">
<label for="pin-preset">Presets</label>
<select id="pin-preset" class="pure-button">
<option value="" selected disabled></option>
</select>
</div>
<hr>
<div class="pure-control-group">
<label for="pin-reset">Reset</label>
<select id="pin-reset"></select>
<div class="popup">Connect to &#xb5;C reset pin for programming and reset-&#xb5;C function</div>
</div>
<div class="pure-control-group">
<label for="pin-isp">ISP/Flash</label>
<select id="pin-isp"></select>
<div class="popup">Second signal to program &#xb5;C.
AVR:not used, esp8266:gpio2, ARM:ISP</div>
</div>
<div class="pure-control-group">
<label for="pin-conn">Conn LED</label>
<select id="pin-conn"></select>
<div class="popup">LED to show WiFi connectivity</div>
</div>
<div class="pure-control-group">
<label for="pin-ser">Serial LED</label>
<select id="pin-ser"></select>
<div class="popup">LED to show serial activity</div>
</div>
<div class="pure-control-group">
<label for="pin-swap">UART pins</label>
<select id="pin-swap" class="pure-button">
<option value="0">normal</option>
<option value="1">swapped</option>
</select>
<div class="popup">Swap UART0 pins to avoid ROM boot message.<br>Normal is
TX on gpio1/TX0 and RX on gpio3/RX0, swapped is TX on gpio15 and RX on gpio13.
</div>
</div>
<div class="pure-control-group">
<label for="pin-rxpup" class="pure-checkbox">RX pull-up</label>
<input id="pin-rxpup" type="checkbox">
<div class="popup">Enable internal 40K pull-up on RX</div>
</div>
<button id="set-pins" type="submit" class="pure-button button-primary">Change!</button>
</form>
</div>
<div style="float:left; padding:2px">
<div class="card">
<h1>System details</h1>
<div id="system-spinner" class="spinner spinner-small"></div>
<table id="system-table" class="pure-table pure-table-horizontal" hidden><tbody>
<tr><td>WiFi mode</td><td id="wifi-mode"></td></tr>
<tr><td>WiFi channel</td><td id="wifi-chan"></td></tr>
<tr><td>Flash chip ID</td><td>
<div>
<span class="system-id"></span>
<div class="popup pop-left">Common IDs: 4016=4MB, 4014=1MB, 4013=512KB</div>
</div>
</div>
<div class="card">
<h1>System details</h1>
<div id="system-spinner" class="spinner spinner-small"></div>
<table id="system-table" class="pure-table pure-table-horizontal" hidden><tbody>
<tr><td>WiFi mode</td><td id="wifi-mode"></td></tr>
<tr><td>WiFi channel</td><td id="wifi-chan"></td></tr>
<tr><td>Flash chip ID</td><td>
<div>
<span class="system-id"></span>
<div class="popup pop-left">Common IDs: 4016=4MB, 4014=1MB, 4013=512KB</div>
</td></tr>
<tr><td>Flash size</td><td>
<div>
<span class="system-size"></span>
<div class="popup pop-left">Size configured into bootloader, must match chip size</div>
</div>
</td></tr>
<tr><td>Current partition</td><td class="system-partition"></td></tr>
<tr><td colspan=2 class="popup-target">Description:<br>
<div class="click-to-edit system-description">
<span class="edit-off" style="display:block; width:auto;"></span>
<textarea class="edit-on" rows=3 maxlength=127 hidden> </textarea>
<div class="popup">Click to edit!<br>A short description or memo for this esp-link
module, 128 chars max</div>
</div>
</td></tr>
<tr><td>Flash size</td><td>
<div>
<span class="system-size"></span>
<div class="popup pop-left">Size configured into bootloader, must match chip size</div>
</td></tr>
</tbody></table>
</div>
</div>
<div style="float:left; padding:2px">
<div class="card">
<h1>Pin assignment</h1>
<div id="pin-spinner" class="spinner spinner-small"></div>
<div id="pin-table" hidden>
<form action="#" id="pinform" class="pure-form pure-form-aligned form-narrow">
<div class="pure-control-group">
<label for="pin-preset">Presets</label>
<select id="pin-preset" class="pure-button">
<option value="" selected disabled></option>
</select>
</div>
</td></tr>
<tr><td>Current partition</td><td class="system-partition"></td></tr>
<tr><td colspan=2 class="popup-target">Description:<br>
<div class="click-to-edit system-description">
<span class="edit-off" style="display:block; width:auto;"></span>
<textarea class="edit-on" rows=3 maxlength=127 hidden> </textarea>
<div class="popup">Click to edit!<br>A short description or memo for this esp-link
module, 128 chars max</div>
<hr>
<div class="pure-control-group">
<label for="pin-reset">Reset</label>
<select id="pin-reset"></select>
<div class="popup">Connect to &#xb5;C reset pin for programming and reset-&#xb5;C function</div>
</div>
<div class="pure-control-group">
<label for="pin-isp">ISP/Flash</label>
<select id="pin-isp"></select>
<div class="popup">Second signal to program &#xb5;C.
AVR:not used, esp8266:gpio2, ARM:ISP</div>
</div>
<div class="pure-control-group">
<label for="pin-conn">Conn LED</label>
<select id="pin-conn"></select>
<div class="popup">LED to show WiFi connectivity</div>
</div>
<div class="pure-control-group">
<label for="pin-ser">Serial LED</label>
<select id="pin-ser"></select>
<div class="popup">LED to show serial activity</div>
</div>
<div class="pure-control-group">
<label for="pin-swap">UART pins</label>
<select id="pin-swap" class="pure-button">
<option value="0">normal</option>
<option value="1">swapped</option>
</select>
<div class="popup">Swap UART0 pins to avoid ROM boot message.<br>Normal is
TX on gpio1/TX0 and RX on gpio3/RX0, swapped is TX on gpio15 and RX on gpio13.
</div>
</td></tr>
</tbody></table>
</div>
<div class="pure-control-group">
<label for="pin-rxpup" class="pure-checkbox">RX pull-up</label>
<input id="pin-rxpup" type="checkbox">
<div class="popup">Enable internal 40K pull-up on RX</div>
</div>
<button id="set-pins" type="submit" class="pure-button button-primary">Change!</button>
</form>
</div>
</div>
</div>
<div class="pure-g">
</div>
</div>
</div>
</div>
<script type="text/javascript">
onLoad(function() {
makeAjaxInput("system", "description");
makeAjaxInput("system", "name");
fetchPins();
getWifiInfo();
getSystemInfo();
bnd($("#pinform"), "submit", setPins);
});
</script>
<script src="ui.js"></script>
<script src="home.js"></script>
</body></html>

@ -1,11 +1,19 @@
<!doctype html>
<html><head>
<title>esp-link</title>
<link rel="stylesheet" href="pure.css">
<link rel="stylesheet" href="style.css">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<div id="layout">
<div id="main">
<div class="header">
<h1>Debug Log</h1>
</div>
<div class="content">
<p>The debug log shows the most recent characters printed by the esp-link software itself to
its own debug log.</p>
<p>The debug log shows the most recent characters printed by the ESP-LINK software itself to its own debug log.</p>
<div class="pure-g">
<p class="pure-u-1-4" style="vertical-align: baseline;width:40%">
<a id="refresh-button" class="pure-button button-primary" href="#">Refresh</a>
@ -14,8 +22,11 @@
<p class="pure-u-3-4" style="vertical-align: baseline;width:60%">
UART debug log:
<a id="dbg-auto" class="dbg-btn pure-button" href="#">auto</a>
&nbsp;
<a id="dbg-off" class="dbg-btn pure-button" href="#">off</a>
&nbsp;
<a id="dbg-on0" class="dbg-btn pure-button" href="#">on uart0</a>
&nbsp;
<a id="dbg-on1" class="dbg-btn pure-button" href="#">on uart1</a>
</p>
</div>
@ -23,38 +34,7 @@
</div>
</div>
</div>
<script type="text/javascript">console_url = "/log/text"</script>
<script src="ui.js"></script>
<script src="console.js"></script>
<script type="text/javascript">
onLoad(function() {
fetchText(100, false);
$("#refresh-button").addEventListener("click", function(e) {
e.preventDefault();
fetchText(100, false);
});
$("#reset-button").addEventListener("click", function (e) {
e.preventDefault();
var co = $("#console");
co.innerHTML = "";
ajaxSpin('POST', "/log/reset",
function (resp) { showNotification("Resetting esp-link"); co.textEnd = 0; fetchText(2000, false); },
function (s, st) { showWarning("Error resetting esp-link"); }
);
});
["auto", "off", "on0", "on1"].forEach(function(mode) {
bnd($('#dbg-'+mode), "click", function(el) {
ajaxJsonSpin('POST', "/log/dbg?mode="+mode,
function(data) { showNotification("UART mode " + data.mode); showDbgMode(data.mode); },
function(s, st) { showWarning("Error setting UART mode: " + st); }
);
});
});
ajaxJson('GET', "/log/dbg", function(data) { showDbgMode(data.mode); }, function() {});
});
</script>
<script src="log_main.js"></script>
</body></html>

@ -1,3 +1,12 @@
<!doctype html>
<html><head>
<title>esp-link</title>
<link rel="stylesheet" href="pure.css">
<link rel="stylesheet" href="style.css">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<div id="layout">
<div id="main">
<div class="header">
<h1>REST &amp; MQTT</h1>
@ -92,13 +101,6 @@
</div>
</div>
</div>
<script src="ui.js"></script>
<script src="mqtt.js"></script>
<script type="text/javascript">
onLoad(function() {
fetchMqtt();
bnd($("#mqtt-form"), "submit", changeMqtt);
bnd($("#mqtt-status-form"), "submit", changeMqttStatus);
});
</script>
</body></html>

@ -1,3 +1,9 @@
onLoad(function() {
fetchMqtt();
bnd($("#mqtt-form"), "submit", changeMqtt);
bnd($("#mqtt-status-form"), "submit", changeMqttStatus);
});
//===== MQTT cards
function changeMqtt(e) {

@ -693,8 +693,8 @@ this the same font stack that Normalize.css sets for the `body`.
font-family: inherit;
font-size: 100%;
padding: 0.5em 1em;
color: #444; /* rgba not supported (IE 8) */
color: rgba(0, 0, 0, 0.80); /* rgba supported */
color: #fff; /* rgba not supported (IE 8) */
color: rgba(f, f, f, 0.80); /* rgba supported */
border: 1px solid #999; /*IE 6/7/8*/
border: none rgba(0, 0, 0, 0); /*IE9 + everything else*/
background-color: #E6E6E6;

@ -1,120 +1,121 @@
<!doctype html>
<html><head>
<title>esp-link</title>
<link rel="stylesheet" href="pure.css">
<link rel="stylesheet" href="style.css">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<div id="layout">
<div id="main">
<div class="header">
<h1>Services</h1>
</div>
<div class="content">
<div class="pure-g">
<div class="pure-u-1 pure-u-md-1-2">
<div class="card">
<h1>
Syslog
<div id="syslog-spinner" class="spinner spinner-small"></div>
</h1>
<form action="#" id="Syslog-form" class="pure-form" hidden>
<div class="pure-form-stacked">
<label>Syslog Host</label>
<input type="text" name="syslog_host" />
<div class="popup">Esp-link sends event/debug info to this syslog host
(hostname:port). Leave empty to disable syslog.</div>
</div>
<div class="pure-form-stacked">
<label>Min Heap</label>
<div>
<input type="text" name="syslog_minheap" />
<div class="popup">Stop sending syslog if free heap drops below this many bytes</div>
</div>
<div>
<label>Filter</label>
<select name="syslog_filter" href="#">
<option value="0">EMERG</option>
<option value="1">ALERT</option>
<option value="2">CRIT</option>
<option value="3">ERR</option>
<option value="4">WARNING</option>
<option value="5">NOTICE</option>
<option value="6">INFO</option>
<option value="7">DEBUG</option>
</select>
<div class="popup">Minimum severity to send</div>
</div>
</div>
<div style="float:left; padding:2px">
<div class="card">
<h1>
Syslog
<div id="syslog-spinner" class="spinner spinner-small"></div>
</h1>
<form action="#" id="Syslog-form" class="pure-form" hidden>
<div class="pure-form-stacked">
<label>Syslog Host</label>
<input type="text" name="syslog_host" />
<div class="popup">Esp-link sends event/debug info to this syslog host
(hostname:port). Leave empty to disable syslog.</div>
</div>
<div class="pure-form-stacked">
<label>Min Heap</label>
<div>
<input type="checkbox" name="syslog_showtick" />
<label>Include esp-link millisecond ticker</label>
<input type="text" name="syslog_minheap" />
<div class="popup">Stop sending syslog if free heap drops below this many bytes</div>
</div>
<div>
<input type="checkbox" name="syslog_showdate" />
<label>Include esp-link datetime</label>
<div class="popup">Some syslog servers rotate log if timestamp is in the past so disable to prevent this</div>
</div>
<button id="Syslog-button" type="submit" class="pure-button button-primary">
Update Syslog settings!
</button>
</form>
</div>
<div class="card">
<h1>
mDNS
<div id="mdns-spinner" class="spinner spinner-small"></div>
</h1>
<form action="#" id="mDNS-form" class="pure-form" hidden>
<div class="form-horizontal">
<input type="checkbox" name="mdns_enable"/>
<label>Enable mDNS</label>
<div class="popup">Esp-link can advertise its hostname and service name (both
with a .local suffix) via multicast DNS.</div>
<label>Filter</label>
<select name="syslog_filter" href="#">
<option value="0">EMERG</option>
<option value="1">ALERT</option>
<option value="2">CRIT</option>
<option value="3">ERR</option>
<option value="4">WARNING</option>
<option value="5">NOTICE</option>
<option value="6">INFO</option>
<option value="7">DEBUG</option>
</select>
<div class="popup">Minimum severity to send</div>
</div>
<br>
<div class="pure-form-stacked">
<label>Service Name</label>
<input type="text" name="mdns_servername"/>
<div class="popup">The default service is http. For the arduino IDE use arduino</div>
</div>
<button id="mDNS-button" type="submit" class="pure-button button-primary">
Update mDNS settings!
</button>
</form>
</div>
</div>
<div>
<input type="checkbox" name="syslog_showtick" />
<label>Include esp-link millisecond ticker</label>
</div>
<div>
<input type="checkbox" name="syslog_showdate" />
<label>Include esp-link datetime</label>
<div class="popup">Some syslog servers rotate log if timestamp is in the past so disable to prevent this</div>
</div>
<button id="Syslog-button" type="submit" class="pure-button button-primary">
Update Syslog settings!
</button>
</form>
</div>
</div>
<div style="float:left; padding:2px">
<div class="card">
<h1>
mDNS
<div id="mdns-spinner" class="spinner spinner-small"></div>
</h1>
<form action="#" id="mDNS-form" class="pure-form" hidden>
<div class="form-horizontal">
<input type="checkbox" name="mdns_enable"/>
<label>Enable mDNS</label>
<div class="popup">Esp-link can advertise its hostname and service name (both
with a .local suffix) via multicast DNS.</div>
</div>
<br>
<div class="pure-form-stacked">
<label>Service Name</label>
<input type="text" name="mdns_servername"/>
<div class="popup">The default service is http. For the arduino IDE use arduino</div>
</div>
<button id="mDNS-button" type="submit" class="pure-button button-primary">
Update mDNS settings!
</button>
</form>
</div>
<div class="pure-u-1 pure-u-md-1-2">
<div class="card">
<h1>
SNTP
<div id="sntp-spinner" class="spinner spinner-small"></div>
</h1>
<form action="#" id="SNTP-form" class="pure-form" hidden>
<div class="pure-form-stacked">
<div>
<label>SNTP Server</label>
<input type="text" name="sntp_server" />
<div class="popup">Simple Network Time Protocol server to query.
Leave empty to disable SNTP</div>
</div>
<div>
<label>Timezone Offset</label>
<input type="text" name="timezone_offset" />
<div class="popup">Offset hours to apply (no daylight savings support)</div>
</div>
</div>
<div style="float:left; padding:2px">
<div class="card">
<h1>
SNTP
<div id="sntp-spinner" class="spinner spinner-small"></div>
</h1>
<form action="#" id="SNTP-form" class="pure-form" hidden>
<div class="pure-form-stacked">
<div>
<label>SNTP Server</label>
<input type="text" name="sntp_server" />
<div class="popup">Simple Network Time Protocol server to query.
Leave empty to disable SNTP</div>
</div>
<button id="SNTP-button" type="submit" class="pure-button button-primary">
Update SNTP settings!
</button>
</form>
</div>
<div>
<label>Timezone Offset (+/- hours)</label>
<input type="text" name="timezone_offset" />
<div class="popup">Offset hours to apply (no daylight savings support)</div>
</div>
</div>
<button id="SNTP-button" type="submit" class="pure-button button-primary">
Update SNTP settings!
</button>
</form>
</div>
</div>
</div>
</div>
</div>
<script src="ui.js"></script>
<script src="services.js"></script>
<script type="text/javascript">
onLoad(function() {
fetchServices();
bnd($("#Syslog-form"), "submit", changeServices);
bnd($("#SNTP-form"), "submit", changeServices);
bnd($("#mDNS-form"), "submit", changeServices);
});
</script>
</body></html>

@ -1,3 +1,10 @@
onLoad(function() {
fetchServices();
bnd($("#Syslog-form"), "submit", changeServices);
bnd($("#SNTP-form"), "submit", changeServices);
bnd($("#mDNS-form"), "submit", changeServices);
});
function changeServices(e) {
e.preventDefault();
var url = "services/update?1=1";

@ -26,6 +26,8 @@ a:hover {
background-color: #eee;
padding: 1em;
margin: 0.5em;
-moz-border-radius: 0.5em;
-webkit-border-radius: 0.5em;
border-radius: 0.5em;
border: 0px solid #000000;
}
@ -39,7 +41,7 @@ a:hover {
}
.click-to-edit input, .click-to-edit textarea {
color: black;
background-color: #eee;
background-color: #F0CAA6;
width: 100%;
}
.click-to-edit span, .click-to-edit div {
@ -49,9 +51,9 @@ a:hover {
width: 100%;
color: #444; /* rgba not supported (IE 8) */
color: rgba(0, 0, 0, 0.80); /* rgba supported */
border: 1px solid #999; /*IE 6/7/8*/
border: 1px solid #111; /*IE 6/7/8*/
border: none rgba(0, 0, 0, 0); /*IE9 + everything else*/
background-color: #E6E6E6;
background-color: #CCCCCC;
text-decoration: none;
border-radius: 2px;
}
@ -155,6 +157,9 @@ fieldset fields {
/* Add transition to containers so they can push in and out */
#layout, #menu, .menu-link {
-webkit-transition: all 0.2s ease-out;
-moz-transition: all 0.2s ease-out;
-ms-transition: all 0.2s ease-out;
-o-transition: all 0.2s ease-out;
transition: all 0.2s ease-out;
}
@ -186,10 +191,10 @@ div.tt {
.content {
margin: 0 auto;
padding: 0 2em;
max-width: 800px;
/*max-width: 800px;*/
margin-bottom: 20px;
line-height: 1.6em;
width: 100%;
/*width: 100%;*/
box-sizing: border-box;
overflow: auto;
}
@ -198,12 +203,12 @@ div.tt {
margin: 0;
color: #333;
text-align: center;
padding: 2.5em 2em 0;
padding: 0.5em;
border-bottom: 1px solid #eee;
background-color: #fc0;
}
.header h1 {
margin: 0.2em 0;
margin: 0;
font-size: 3em;
font-weight: 300;
}
@ -251,6 +256,8 @@ input.inline {
/* Text console */
pre.console {
background-color: #663300;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
border-radius: 5px;
border: 0px solid #000000;
color: #66ff66;
@ -495,6 +502,8 @@ pre.console a {
height: 50px;
width: 50px;
-webkit-animation: rotation 1s infinite linear;
-moz-animation: rotation 1s infinite linear;
-o-animation: rotation 1s infinite linear;
animation: rotation 1s infinite linear;
border-left: 10px solid rgba(204, 51, 0, 0.15);
border-right: 10px solid rgba(204, 51, 0, 0.15);
@ -518,6 +527,23 @@ pre.console a {
}
}
@-moz-keyframes rotation {
from {
-moz-transform: rotate(0deg);
}
to {
-moz-transform: rotate(359deg);
}
}
@-o-keyframes rotation {
from {
-o-transform: rotate(0deg);
}
to {
-o-transform: rotate(359deg);
}
}
@keyframes rotation {
from {
-webkit-transform: rotate(0deg);
@ -528,3 +554,36 @@ pre.console a {
transform: rotate(359deg);
}
}
a
{
color: #5873DD;
font-family: Arial;
font-size: 10pt;
font-weight: bold;
text-decoration: none;
}
a.btn
{
white-space: nowrap;
text-align: center;
vertical-align: middle;
display: inline-block;
border-radius: 6px;
font-size: 16pt;
line-height: 1.33;
padding: 10px 10px;
}
a.btn-yes
{
background-color: #5CB85C;
color: white;
}
a.btn-no
{
background-color: #D9534F;
color: white;
}

@ -330,6 +330,15 @@ function makeAjaxInput(klass, field) {
eoff.setAttribute('hidden','');
domForEach(eon, function(el){ el.removeAttribute('hidden'); });
eon[0].select();
old_hostname = eon[0].value;
return false;
}
var just_close = function()
{
domForEach(eon, function(el){ el.setAttribute('hidden',''); });
eoff.removeAttribute('hidden');
setEditToClick(klass+"-"+field, old_hostname);
return false;
}
@ -347,9 +356,10 @@ function makeAjaxInput(klass, field) {
}
bnd(eoff, "click", function(){return enableEditToClick();});
bnd(eon[0], "blur", function(){return submitEditToClick(eon[0].value);});
bnd(eon[0], "blur", function(){return just_close();});
bnd(eon[0], "keyup", function(ev){
if ((ev||window.event).keyCode==13) return submitEditToClick(eon[0].value);
else if ((ev||window.event).keyCode==27) return just_close();
});
});
}
@ -369,11 +379,17 @@ function setEditToClick(klass, value) {
//===== Notifications
var notifTimeout = null;
function showWarning(text) {
var el = $("#warning");
el.innerHTML = text;
el.removeAttribute('hidden');
window.scrollTo(0, 0);
if (notifTimeout != null) clearTimeout(notifTimeout);
notifTimout = setTimeout(function() {
el.setAttribute('hidden', '');
notifTimout = null;
}, 6000);
}
function hideWarning() {
el = $("#warning").setAttribute('hidden', '');

@ -1,50 +1,74 @@
<!doctype html>
<html><head>
<title>esp-link</title>
<link rel="stylesheet" href="../pure.css">
<link rel="stylesheet" href="../style.css">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<div id="layout">
<div id="main">
<div class="header">
<h1>WiFi Soft-AP Configuration</h1>
</div>
<div class="content">
<div class="pure-g">
<div class="pure-u-1 pure-u-md-1-2">
<div class="card">
<div style="float:left; padding:2px">
<div class="card">
<h1>Soft-AP State</h1>
<div id="wifi-spinner" class="spinner spinner-small">
</div>
<div id="wifi-spinner" class="spinner spinner-small"></div>
<table id="wifi-table" class="pure-table pure-table-horizontal" hidden><tbody>
<tr><td>WiFi mode</td><td id="wifi-mode"></td></tr>
<tr><td>Soft-AP SSID</td><td id="wifi-apssid"></td></tr>
<tr><td>Soft-AP Password</td><td id="wifi-appass"></td></tr>
<tr><td>Soft-AP Channel</td><td id="wifi-apchan"></td></tr>
<tr><td>Soft-AP Max Conn</td><td id="wifi-apmaxc"></td></tr>
<tr><td>Soft-AP Hidden</td><td id="wifi-aphidd"></td></tr>
<tr><td>Soft-AP Beacon Int</td><td id="wifi-apbeac"></td></tr>
<tr><td>Soft-AP Auth Mode</td><td id="wifi-apauth"></td></tr>
<tr><td>Soft-AP MAC</td><td id="wifi-apmac"></td></tr>
<tr><td colspan="2" id="wifi-apwarn"></td></tr>
<tr><td>WiFi mode</td><td id="wifi-mode"></td></tr>
<tr><td>Soft-AP SSID</td><td id="wifi-apssid"></td></tr>
<tr><td>Soft-AP Password</td><td id="wifi-appass"></td></tr>
<tr><td>Soft-AP Channel</td><td id="wifi-apchan"></td></tr>
<tr><td>Soft-AP Max Conn</td><td id="wifi-apmaxc"></td></tr>
<tr><td>Soft-AP Hidden</td><td id="wifi-aphidd"></td></tr>
<tr><td>Soft-AP Beacon Interval</td><td id="wifi-apbeac"></td></tr>
<tr><td>Soft-AP Auth Mode</td><td id="wifi-apauth"></td></tr>
<tr><td>Soft-AP MAC</td><td id="wifi-apmac"></td></tr>
<tr><td colspan="2" id="wifi-apwarn"></td></tr>
</tbody> </table>
</div><!-- card-->
</div><!-- pure-u-1 -->
<div class="pure-u-1 pure-u-md-1-2">
</div>
</div>
<div style="float:left; padding:2px">
<div class="card">
<h1>Soft-AP Settings</h1>
<div id="AP_Settings-spinner" class="spinner spinner-small"></div>
<form action="#" id="AP_Settings-form" class="pure-form" hidden>
<legend>Soft-AP main settings, use with care!</legend>
<h1>Soft-AP Settings</h1>
<div id="AP_Settings-spinner" class="spinner spinner-small"></div>
<form action="#" name="ap_form" id="AP_Settings-form" class="pure-form" hidden>
<legend>Soft-AP main settings, use with care!</legend>
<div class="pure-form-stacked">
<label>Soft-AP SSID</label>
<input type="text" name="ap_ssid" />
<div class="popup">Change the name of your AP!</div>
</div>
<div class="pure-form-stacked">
<label>Soft-AP Password</label>
<input type="text" name="ap_password" />
<div class="popup">Password must be at least 8 chars long!</div>
</div>
<div class="pure-form-stacked">
<legend>Soft-AP Advanced Settings</legend>
</div>
<div class="form-horizontal">
<label for="AP_Settings-ron" style="margin-right:1em">
<input type="radio" name="ap" value="on" id="AP_Settings-ron"/> Show
</label>
<label for="AP_Settings-roff" style="margin-right:1em">
<input type="radio" name="ap" value="off" id="AP_Settings-roff"/> Hide
</label>
</div>
<div id="AP_Settings-off" class="pure-form-stacked"></div>
<div id="AP_Settings-on" class="pure-form-stacked">
<div class="pure-form-stacked">
<label>Soft-AP SSID</label>
<input type="text" name="ap_ssid" />
<div class="popup">Change the name of your AP!</div>
<label>Soft-AP Max Connections</label>
<input type="text" name="ap_maxconn" />
<div class="popup">Max 4 ( default 4 )</div>
</div>
<div class="pure-form-stacked">
<label>Soft-AP Password</label>
<input type="text" name="ap_password" />
<div class="popup">Password must be at least 8 chars long!</div>
<label>Soft-AP Beacon Interval (ms)</label>
<input type="text" name="ap_beacon" />
<div class="popup">Between 100 - 60000 ms ( default 100ms )</div>
</div>
<div class="pure-form-stacked">
<label>Soft-AP Auth Mode</label>
<select name="ap_authmode" href="#">
@ -56,47 +80,20 @@
</select>
<div class="popup">Default WPA_WPA2_PSK</div>
</div>
<div class="pure-form-stacked">
<label>Soft-AP Max Connections</label>
<input type="text" name="ap_maxconn" />
<div class="popup">Max 4 ( default 4 )</div>
</div>
<div class="pure-form-stacked">
<label>Soft-AP Beacon Interval</label>
<input type="text" name="ap_beacon" />
<div class="popup">Between 100 - 60000 ms ( default 100ms )</div>
</div>
<div class="form-horizontal">
<label><input type="checkbox" name="ap_hidden" />Soft-AP SSID hidden</label>
<div class="popup">Check this box to hide you Soft-AP SSID ( default Not Hidden )</div>
<div class="popup">Check this box to hide your Soft-AP SSID ( default Not Hidden )</div>
</div>
<button id="AP_Settings-button" type="submit" class="pure-button button-primary">
Change Soft-AP settings!
</button>
</form>
</div>
</div><!-- pure-u-1 -->
</div><!-- pure-g -->
</div><!-- content -->
</div><!-- main -->
</div><!-- layout -->
<script type="text/javascript">
</script>
</div>
<button id="AP_Settings-button" type="submit" class="pure-button button-primary">
Change Soft-AP settings
</button>
</form>
</div>
</div>
</div>
</div>
</div>
<script src="../ui.js"></script>
<script src="wifiAp.js"></script>
<script type="text/javascript">
onLoad(function() {
// Show info about AP
getWifiInfo();
// Fetch actual settings
fetchApSettings();
// Wire-up form
bnd($("#AP_Settings-form"), "submit", changeApSettings);
});
</script>
</body></html>

@ -7,7 +7,7 @@ specials["ap_beacon"] = "Beacon Interval";
function changeWifiMode(m) {
blockScan = 1;
hideWarning();
ajaxSpin("POST", "setmode?mode=" + m, function(resp) {
ajaxSpin("POST", "/wifi/setmode?mode=" + m, function(resp) {
showNotification("Mode changed");
window.setTimeout(getWifiInfo, 100);
blockScan = 0;
@ -83,3 +83,28 @@ function fetchApSettings() {
window.setTimeout(fetchApSettings, 1000);
});
}
function doApAdvanced() {
$('#AP_Settings-on').removeAttribute('hidden');
$("#AP_Settings-off").setAttribute("hidden", "");
$("#AP_Settings-roff").removeAttribute("checked");
}
function undoApAdvanced(){
$("#AP_Settings-on").setAttribute("hidden", "");
$("#AP_Settings-off").removeAttribute("hidden");
$("#AP_Settings-roff").setAttribute("checked", "");
}
onLoad(function() {
// Show info about AP
getWifiInfo();
// Fetch actual settings
fetchApSettings();
// Hide advanced settings
undoApAdvanced();
document.ap_form.ap.value='off';
bnd($("#AP_Settings-ron"), "click", doApAdvanced);
bnd($("#AP_Settings-roff"), "click", undoApAdvanced);
bnd($("#AP_Settings-form"), "submit", changeApSettings);
});

@ -1,47 +1,37 @@
<!doctype html>
<html><head>
<title>esp-link</title>
<link rel="stylesheet" href="../pure.css">
<link rel="stylesheet" href="../style.css">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<div id="layout">
<div id="main">
<div class="header">
<h1>WiFi Station Configuration</h1>
</div>
<div class="content">
<div class="pure-g">
<div class="pure-u-1 pure-u-md-1-2"><div class="card">
<div style="float:left; padding:2px">
<div class="card">
<h1>WiFi State</h1>
<div id="wifi-spinner" class="spinner spinner-small"></div>
<table id="wifi-table" class="pure-table pure-table-horizontal" hidden><tbody>
<tr><td>WiFi mode</td><td id="wifi-mode"></td></tr>
<tr><td>WiFi channel</td><td id="wifi-chan"></td></tr>
<tr><td>Configured network</td><td id="wifi-ssid"></td></tr>
<tr><td>WiFi status</td><td id="wifi-status"></td></tr>
<tr><td>WiFi address</td><td id="wifi-ip"></td></tr>
<tr><td>WiFi rssi</td><td id="wifi-rssi"></td></tr>
<tr><td>WiFi phy</td><td id="wifi-phy"></td></tr>
<tr><td>WiFi MAC</td><td id="wifi-mac"></td></tr>
<tr><td colspan="2" id="wifi-warn"></td></tr>
<tr><td>WiFi mode</td><td id="wifi-mode"></td></tr>
<tr><td>WiFi channel</td><td id="wifi-chan"></td></tr>
<tr><td>Configured network</td><td id="wifi-ssid"></td></tr>
<tr><td>WiFi status</td><td id="wifi-status"></td></tr>
<tr><td>WiFi address</td><td id="wifi-ip"></td></tr>
<tr><td>WiFi rssi</td><td id="wifi-rssi"></td></tr>
<tr><td>WiFi phy</td><td id="wifi-phy"></td></tr>
<tr><td>WiFi MAC</td><td id="wifi-mac"></td></tr>
<tr><td colspan="2" id="wifi-warn"></td></tr>
</tbody> </table>
</div>
</div>
<div class="pure-u-1 pure-u-md-1-2"><div class="card">
<h1>WiFi Association</h1>
<p id="reconnect" style="color: #600" hidden></p>
<form action="#" id="wifiform" class="pure-form pure-form-stacked">
<legend>To connect to a WiFi network, please select one of the detected networks,
enter the password, and hit the connect button...</legend>
<label>Network SSID</label>
<div id="aps">Scanning... <div class="spinner spinner-small"></div></div>
<label for="opt-hiddenssid">
<input type="radio" name="essid" value="_hidden_ssid_" id="opt-hiddenssid">
<input type="text" id="hidden-ssid" value="" style="width:auto; display:inline-block; margin-left: 0.7em">
</label>
<label>WiFi password, if applicable:</label>
<input id="wifi-passwd" type="password" name="passwd" placeholder="password">
<button id="connect-button" type="submit" class="pure-button button-primary">Connect!</button>
</form>
</div></div>
</div>
<div class="pure-g">
<div class="pure-u-1 pure-u-md-1-2"><div class="card">
<div style="float:left; padding:2px">
<div class="card">
<h1>Special Settings</h1>
<form action="#" id="specform" class="pure-form">
<legend>Special settings, use with care!</legend>
@ -64,23 +54,30 @@
</div>
<button id="special-button" type="submit" class="pure-button button-primary">Change!</button>
</form>
</div></div>
</div>
</div>
<div style="float:left; padding:2px">
<div class="card">
<h1>WiFi Association</h1>
<p id="reconnect" style="color: #600" hidden></p>
<form action="#" id="wifiform" class="pure-form pure-form-stacked">
<legend>To connect to a WiFi network - choose one of detected networks (or enter a SSID),<br>
enter the password, and hit the CONNECT button...</legend>
<label>Network SSID</label>
<div id="aps">Scanning... <div class="spinner spinner-small"></div></div>
<label for="opt-hiddenssid">
<input type="radio" name="essid" value="_hidden_ssid_" id="opt-hiddenssid" />
<input type="text" id="hidden-ssid" value="" style="width:auto; display:inline-block; margin-left: 0.7em" />
</label>
<label>WiFi password, if applicable:</label>
<input id="wifi-passwd" type="password" name="passwd" placeholder="password" />
<button id="connect-button" type="submit" class="pure-button button-primary">Connect</button>
</form>
</div>
</div>
</div>
</div>
</div>
<script type="text/javascript">
</script>
<script src="../ui.js"></script>
<script src="wifiSta.js"></script>
<script type="text/javascript">
onLoad(function() {
getWifiInfo();
bnd($("#wifiform"), "submit", changeWifiAp);
bnd($("#specform"), "submit", changeSpecial);
bnd($("#dhcp-ron"), "click", doDhcp);
bnd($("#dhcp-roff"), "click", doStatic);
scanTimeout = window.setTimeout(scanAPs, 500);
});
</script>
</body></html>

@ -201,3 +201,12 @@ function doStatic() {
$('#dhcp-off').removeAttribute('hidden');
$('#dhcp-on').setAttribute('hidden', '');
}
onLoad(function() {
getWifiInfo();
bnd($("#wifiform"), "submit", changeWifiAp);
bnd($("#specform"), "submit", changeSpecial);
bnd($("#dhcp-ron"), "click", doDhcp);
bnd($("#dhcp-roff"), "click", doStatic);
scanTimeout = window.setTimeout(scanAPs, 500);
});

@ -31,10 +31,10 @@ int ICACHE_FLASH_ATTR authBasic(HttpdConnData *connData) {
r=httpdGetHeader(connData, "Authorization", hdr, sizeof(hdr));
if (r && strncmp(hdr, "Basic", 5)==0) {
r=base64_decode(strlen(hdr)-6, hdr+6, sizeof(userpass), (unsigned char *)userpass);
r=ubase64_decode(strlen(hdr)-6, hdr+6, sizeof(userpass), (unsigned char *)userpass);
if (r<0) r=0; //just clean out string on decode error
userpass[r]=0; //zero-terminate user:pass string
// os_printf("Auth: %s\n", userpass);
// DBG("Auth: %s\n", userpass);
while (((AuthGetUserPw)(connData->cgiArg))(connData, no,
user, AUTH_MAX_USER_LEN, pass, AUTH_MAX_PASS_LEN)) {
//Check user/pass against auth header

@ -39,7 +39,7 @@ static int ICACHE_FLASH_ATTR base64decode(const char in[4], char out[3]) {
#endif
/* decode a base64 string in one shot */
int ICACHE_FLASH_ATTR base64_decode(size_t in_len, const char *in, size_t out_len, unsigned char *out) {
int ICACHE_FLASH_ATTR ubase64_decode(size_t in_len, const char *in, size_t out_len, unsigned char *out) {
unsigned int ii, io;
uint32_t v;
unsigned int rem;

@ -1,6 +1,6 @@
#ifndef BASE64_H
#define BASE64_H
int base64_decode(size_t in_len, const char *in, size_t out_len, unsigned char *out);
int ubase64_decode(size_t in_len, const char *in, size_t out_len, unsigned char *out);
#endif

@ -396,7 +396,7 @@ static void ICACHE_FLASH_ATTR httpdProcessRequest(HttpdConnData *conn) {
return;
}
else {
if (!(r == HTTPD_CGI_NOTFOUND || r == HTTPD_CGI_AUTHENTICATED)) {
if (r == HTTPD_CGI_NOTFOUND) {
os_printf("%shandler for %s returned invalid result %d\n", connStr, conn->url, r);
}
//URL doesn't want to handle the request: either the data isn't found or there's no

@ -37,7 +37,10 @@
// If defined, the default hostname for DHCP will include the chip ID to make it unique
#undef CHIP_IN_HOSTNAME
extern char* esp_link_version;
extern char esp_link_version[];
extern char esp_link_date[];
extern char esp_link_time[];
extern char esp_link_build[];
extern uint8_t UTILS_StrToIP(const char* str, void *ip);
#endif

Loading…
Cancel
Save