Initial commit with Arduino and client
This commit is contained in:
@@ -0,0 +1,336 @@
|
||||
#include "definitions.h"
|
||||
|
||||
// ***************************************************************************
|
||||
// Load libraries for: WebServer / WiFiManager / WebSockets
|
||||
// ***************************************************************************
|
||||
#include <ESP8266WiFi.h> //https://github.com/esp8266/Arduino
|
||||
|
||||
// needed for library WiFiManager
|
||||
#include <DNSServer.h>
|
||||
#include <ESP8266WebServer.h>
|
||||
#include <WiFiManager.h> //https://github.com/tzapu/WiFiManager
|
||||
|
||||
#include <WiFiClient.h>
|
||||
#include <ESP8266mDNS.h>
|
||||
#include <FS.h>
|
||||
|
||||
#include <WebSockets.h> //https://github.com/Links2004/arduinoWebSockets
|
||||
#include <WebSocketsServer.h>
|
||||
|
||||
|
||||
// ***************************************************************************
|
||||
// Instanciate HTTP(80) / WebSockets(81) Server
|
||||
// ***************************************************************************
|
||||
ESP8266WebServer server ( 80 );
|
||||
WebSocketsServer webSocket = WebSocketsServer(81);
|
||||
|
||||
|
||||
// ***************************************************************************
|
||||
// Load libraries / Instanciate Neopixel
|
||||
// ***************************************************************************
|
||||
#include <Adafruit_NeoPixel.h>
|
||||
#ifdef __AVR__
|
||||
#include <avr/power.h>
|
||||
#endif
|
||||
|
||||
// Parameter 1 = number of pixels in strip
|
||||
// Parameter 2 = Arduino pin number (most are valid)
|
||||
// Parameter 3 = pixel type flags, add together as needed:
|
||||
// NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
|
||||
// NEO_KHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
|
||||
// NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products)
|
||||
// NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
|
||||
Adafruit_NeoPixel strip = Adafruit_NeoPixel(NUMLEDS, PIN, NEO_GRB + NEO_KHZ800);
|
||||
|
||||
// IMPORTANT: To reduce NeoPixel burnout risk, add 1000 uF capacitor across
|
||||
// pixel power leads, add 300 - 500 Ohm resistor on first pixel's data input
|
||||
// and minimize distance between Arduino and first pixel. Avoid connecting
|
||||
// on a live circuit...if you must, connect GND first.
|
||||
|
||||
|
||||
// ***************************************************************************
|
||||
// Load library "ticker" for blinking status led
|
||||
// ***************************************************************************
|
||||
#include <Ticker.h>
|
||||
Ticker ticker;
|
||||
|
||||
void tick()
|
||||
{
|
||||
//toggle state
|
||||
int state = digitalRead(BUILTIN_LED); // get the current state of GPIO1 pin
|
||||
digitalWrite(BUILTIN_LED, !state); // set pin to the opposite state
|
||||
}
|
||||
|
||||
|
||||
// ***************************************************************************
|
||||
// Callback for WiFiManager library when config mode is entered
|
||||
// ***************************************************************************
|
||||
//gets called when WiFiManager enters configuration mode
|
||||
void configModeCallback (WiFiManager *myWiFiManager) {
|
||||
DBG_OUTPUT_PORT.println("Entered config mode");
|
||||
DBG_OUTPUT_PORT.println(WiFi.softAPIP());
|
||||
//if you used auto generated SSID, print it
|
||||
DBG_OUTPUT_PORT.println(myWiFiManager->getConfigPortalSSID());
|
||||
//entered config mode, make led toggle faster
|
||||
ticker.attach(0.2, tick);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ***************************************************************************
|
||||
// Include: Webserver
|
||||
// ***************************************************************************
|
||||
#include "spiffs_webserver.h"
|
||||
|
||||
// ***************************************************************************
|
||||
// Include: Request handlers
|
||||
// ***************************************************************************
|
||||
#include "request_handlers.h"
|
||||
|
||||
// ***************************************************************************
|
||||
// Include: Color modes
|
||||
// ***************************************************************************
|
||||
#include "colormodes.h"
|
||||
|
||||
|
||||
|
||||
// ***************************************************************************
|
||||
// MAIN
|
||||
// ***************************************************************************
|
||||
void setup() {
|
||||
DBG_OUTPUT_PORT.begin(115200);
|
||||
|
||||
// set builtin led pin as output
|
||||
pinMode(BUILTIN_LED, OUTPUT);
|
||||
// start ticker with 0.5 because we start in AP mode and try to connect
|
||||
ticker.attach(0.6, tick);
|
||||
|
||||
// ***************************************************************************
|
||||
// Setup: WiFiManager
|
||||
// ***************************************************************************
|
||||
//Local intialization. Once its business is done, there is no need to keep it around
|
||||
WiFiManager wifiManager;
|
||||
//reset settings - for testing
|
||||
//wifiManager.resetSettings();
|
||||
|
||||
//set callback that gets called when connecting to previous WiFi fails, and enters Access Point mode
|
||||
wifiManager.setAPCallback(configModeCallback);
|
||||
|
||||
//fetches ssid and pass and tries to connect
|
||||
//if it does not connect it starts an access point with the specified name
|
||||
//here "AutoConnectAP"
|
||||
//and goes into a blocking loop awaiting configuration
|
||||
if (!wifiManager.autoConnect()) {
|
||||
DBG_OUTPUT_PORT.println("failed to connect and hit timeout");
|
||||
//reset and try again, or maybe put it to deep sleep
|
||||
ESP.reset();
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
//if you get here you have connected to the WiFi
|
||||
DBG_OUTPUT_PORT.println("connected...yeey :)");
|
||||
ticker.detach();
|
||||
//keep LED on
|
||||
digitalWrite(BUILTIN_LED, LOW);
|
||||
|
||||
|
||||
// ***************************************************************************
|
||||
// Setup: Neopixel
|
||||
// ***************************************************************************
|
||||
strip.begin();
|
||||
strip.setBrightness(brightness);
|
||||
strip.show(); // Initialize all pixels to 'off'
|
||||
|
||||
|
||||
// ***************************************************************************
|
||||
// Setup: MDNS responder
|
||||
// ***************************************************************************
|
||||
MDNS.begin(HOSTNAME);
|
||||
DBG_OUTPUT_PORT.print("Open http://");
|
||||
DBG_OUTPUT_PORT.print(HOSTNAME);
|
||||
DBG_OUTPUT_PORT.println(".local/edit to see the file browser");
|
||||
|
||||
|
||||
// ***************************************************************************
|
||||
// Setup: WebSocket server
|
||||
// ***************************************************************************
|
||||
webSocket.begin();
|
||||
webSocket.onEvent(webSocketEvent);
|
||||
|
||||
|
||||
// ***************************************************************************
|
||||
// Setup: SPIFFS
|
||||
// ***************************************************************************
|
||||
SPIFFS.begin();
|
||||
{
|
||||
Dir dir = SPIFFS.openDir("/");
|
||||
while (dir.next()) {
|
||||
String fileName = dir.fileName();
|
||||
size_t fileSize = dir.fileSize();
|
||||
DBG_OUTPUT_PORT.printf("FS File: %s, size: %s\n", fileName.c_str(), formatBytes(fileSize).c_str());
|
||||
}
|
||||
DBG_OUTPUT_PORT.printf("\n");
|
||||
}
|
||||
|
||||
// ***************************************************************************
|
||||
// Setup: SPIFFS Webserver handler
|
||||
// ***************************************************************************
|
||||
//list directory
|
||||
server.on("/list", HTTP_GET, handleFileList);
|
||||
//load editor
|
||||
server.on("/edit", HTTP_GET, [](){
|
||||
if(!handleFileRead("/edit.htm")) server.send(404, "text/plain", "FileNotFound");
|
||||
});
|
||||
//create file
|
||||
server.on("/edit", HTTP_PUT, handleFileCreate);
|
||||
//delete file
|
||||
server.on("/edit", HTTP_DELETE, handleFileDelete);
|
||||
//first callback is called after the request has ended with all parsed arguments
|
||||
//second callback handles file uploads at that location
|
||||
server.on("/edit", HTTP_POST, [](){ server.send(200, "text/plain", ""); }, handleFileUpload);
|
||||
//get heap status, analog input value and all GPIO statuses in one json call
|
||||
server.on("/status", HTTP_GET, [](){
|
||||
String json = "{";
|
||||
json += "\"heap\":"+String(ESP.getFreeHeap());
|
||||
json += ", \"analog\":"+String(analogRead(A0));
|
||||
json += ", \"gpio\":"+String((uint32_t)(((GPI | GPO) & 0xFFFF) | ((GP16I & 0x01) << 16)));
|
||||
json += "}";
|
||||
server.send(200, "text/json", json);
|
||||
json = String();
|
||||
});
|
||||
|
||||
|
||||
//called when the url is not defined here
|
||||
//use it to load content from SPIFFS
|
||||
server.onNotFound([](){
|
||||
if(!handleFileRead(server.uri()))
|
||||
handleNotFound();
|
||||
});
|
||||
|
||||
|
||||
server.on("/upload", handleMinimalUpload);
|
||||
|
||||
// ***************************************************************************
|
||||
// Setup: SPIFFS Webserver handler
|
||||
// ***************************************************************************
|
||||
server.on("/brightness", []() {
|
||||
brightness = server.arg("p").toInt();
|
||||
if (brightness > 255) {
|
||||
brightness = 255;
|
||||
}
|
||||
if (brightness < 0) {
|
||||
brightness = 0;
|
||||
}
|
||||
strip.setBrightness(brightness);
|
||||
|
||||
if (mode == HOLD) {
|
||||
mode = ALL;
|
||||
}
|
||||
|
||||
getStatusJSON();
|
||||
});
|
||||
|
||||
server.on("/status", []() {
|
||||
getStatusJSON();
|
||||
});
|
||||
|
||||
server.on("/off", []() {
|
||||
exit_func = true;
|
||||
mode = OFF;
|
||||
getArgs();
|
||||
getStatusJSON();
|
||||
});
|
||||
|
||||
server.on("/all", []() {
|
||||
exit_func = true;
|
||||
mode = ALL;
|
||||
getArgs();
|
||||
getStatusJSON();
|
||||
});
|
||||
|
||||
server.on("/wipe", []() {
|
||||
exit_func = true;
|
||||
mode = WIPE;
|
||||
getArgs();
|
||||
getStatusJSON();
|
||||
});
|
||||
|
||||
server.on("/rainbow", []() {
|
||||
exit_func = true;
|
||||
mode = RAINBOW;
|
||||
getArgs();
|
||||
getStatusJSON();
|
||||
});
|
||||
|
||||
server.on("/rainbowCycle", []() {
|
||||
exit_func = true;
|
||||
mode = RAINBOWCYCLE;
|
||||
getArgs();
|
||||
getStatusJSON();
|
||||
});
|
||||
|
||||
server.on("/theaterchase", []() {
|
||||
exit_func = true;
|
||||
mode = THEATERCHASE;
|
||||
getArgs();
|
||||
getStatusJSON();
|
||||
});
|
||||
|
||||
server.on("/theaterchaseRainbow", []() {
|
||||
exit_func = true;
|
||||
mode = THEATERCHASERAINBOW;
|
||||
getArgs();
|
||||
getStatusJSON();
|
||||
});
|
||||
|
||||
server.on("/tv", []() {
|
||||
exit_func = true;
|
||||
mode = TV;
|
||||
getArgs();
|
||||
getStatusJSON();
|
||||
});
|
||||
|
||||
server.begin();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
server.handleClient();
|
||||
webSocket.loop();
|
||||
|
||||
// Simple statemachine that handles the different modes
|
||||
if (mode == OFF) {
|
||||
colorWipe(strip.Color(0, 0, 0), 50);
|
||||
mode = HOLD;
|
||||
}
|
||||
if (mode == ALL) {
|
||||
uint16_t i;
|
||||
for (i = 0; i < strip.numPixels(); i++) {
|
||||
strip.setPixelColor(i, main_color.red, main_color.green, main_color.blue);
|
||||
}
|
||||
strip.show();
|
||||
mode = HOLD;
|
||||
}
|
||||
if (mode == WIPE) {
|
||||
colorWipe(strip.Color(main_color.red, main_color.green, main_color.blue), delay_ms);
|
||||
}
|
||||
if (mode == RAINBOW) {
|
||||
rainbow(delay_ms);
|
||||
}
|
||||
if (mode == RAINBOWCYCLE) {
|
||||
rainbowCycle(delay_ms);
|
||||
}
|
||||
if (mode == THEATERCHASE) {
|
||||
theaterChase(strip.Color(main_color.red, main_color.green, main_color.blue), delay_ms);
|
||||
}
|
||||
if (mode == THEATERCHASERAINBOW) {
|
||||
theaterChaseRainbow(delay_ms);
|
||||
}
|
||||
if (mode == HOLD) {
|
||||
if (exit_func) {
|
||||
exit_func = false;
|
||||
}
|
||||
}
|
||||
if (mode == TV) {
|
||||
tv();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,218 @@
|
||||
// ***************************************************************************
|
||||
// Color modes
|
||||
// ***************************************************************************
|
||||
|
||||
int dipInterval = 10;
|
||||
int darkTime = 250;
|
||||
unsigned long currentDipTime;
|
||||
unsigned long dipStartTime;
|
||||
unsigned long currentMillis;
|
||||
int ledState = LOW;
|
||||
long previousMillis = 0;
|
||||
int led = 5;
|
||||
int interval = 2000;
|
||||
int twitch = 50;
|
||||
int dipCount = 0;
|
||||
int analogLevel = 100;
|
||||
boolean timeToDip = false;
|
||||
int ledStates[12];
|
||||
|
||||
void hsb2rgbAN1(uint16_t index, uint8_t sat, uint8_t bright, uint8_t myled) {
|
||||
// Source: https://blog.adafruit.com/2012/03/14/constant-brightness-hsb-to-rgb-algorithm/
|
||||
uint8_t temp[5], n = (index >> 8) % 3;
|
||||
temp[0] = temp[3] = (uint8_t)(( (sat ^ 255) * bright) / 255);
|
||||
temp[1] = temp[4] = (uint8_t)((((( (index & 255) * sat) / 255) + (sat ^ 255)) * bright) / 255);
|
||||
temp[2] = (uint8_t)(((((((index & 255) ^ 255) * sat) / 255) + (sat ^ 255)) * bright) / 255);
|
||||
|
||||
strip.setPixelColor(myled, temp[n + 2], temp[n + 1], temp[n]);
|
||||
}
|
||||
|
||||
|
||||
void updateLed (int led, int brightness) {
|
||||
ledStates[led] = brightness;
|
||||
|
||||
for (int i=0;i<12;i++)
|
||||
{
|
||||
uint16_t index = (i%3 == 0) ? 400 : random(0,767);
|
||||
hsb2rgbAN1(index, 200, ledStates[i], i);
|
||||
}
|
||||
strip.show();
|
||||
}
|
||||
|
||||
|
||||
// Input a value 0 to 255 to get a color value.
|
||||
// The colours are a transition r - g - b - back to r.
|
||||
uint32_t Wheel(byte WheelPos) {
|
||||
WheelPos = 255 - WheelPos;
|
||||
if (WheelPos < 85) {
|
||||
return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
|
||||
}
|
||||
if (WheelPos < 170) {
|
||||
WheelPos -= 85;
|
||||
return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
|
||||
}
|
||||
WheelPos -= 170;
|
||||
return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
|
||||
}
|
||||
|
||||
|
||||
// See: http://forum.mysensors.org/topic/85/phoneytv-for-vera-is-here/13
|
||||
void tv() {
|
||||
checkForRequests();
|
||||
if (exit_func) {
|
||||
exit_func = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (timeToDip == false)
|
||||
{
|
||||
currentMillis = millis();
|
||||
if(currentMillis-previousMillis > interval)
|
||||
{
|
||||
previousMillis = currentMillis;
|
||||
interval = random(750,4001);//Adjusts the interval for more/less frequent random light changes
|
||||
twitch = random(40,100);// Twitch provides motion effect but can be a bit much if too high
|
||||
dipCount = dipCount++;
|
||||
}
|
||||
if(currentMillis-previousMillis<twitch)
|
||||
{
|
||||
led=random(0,11);
|
||||
analogLevel=random(50,255);// set the range of the 3 pwm leds
|
||||
ledState = ledState == LOW ? HIGH: LOW; // if the LED is off turn it on and vice-versa:
|
||||
|
||||
updateLed(led, (ledState) ? 255 : 0);
|
||||
|
||||
if (dipCount > dipInterval)
|
||||
{
|
||||
DBG_OUTPUT_PORT.println("dip");
|
||||
timeToDip = true;
|
||||
dipCount = 0;
|
||||
dipStartTime = millis();
|
||||
darkTime = random(50,150);
|
||||
dipInterval = random(5,250);// cycles of flicker
|
||||
}
|
||||
//strip.show();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG_OUTPUT_PORT.println("Dip Time");
|
||||
currentDipTime = millis();
|
||||
if (currentDipTime - dipStartTime < darkTime)
|
||||
{
|
||||
for (int i=3;i<9;i++)
|
||||
{
|
||||
updateLed (i, 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
timeToDip = false;
|
||||
}
|
||||
strip.show();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Fill the dots one after the other with a color
|
||||
void colorWipe(uint32_t c, uint8_t wait) {
|
||||
for (uint16_t i = 0; i < strip.numPixels(); i++) {
|
||||
strip.setPixelColor(i, c);
|
||||
strip.show();
|
||||
|
||||
checkForRequests();
|
||||
if (exit_func) {
|
||||
exit_func = false;
|
||||
return;
|
||||
}
|
||||
|
||||
delay(wait);
|
||||
}
|
||||
mode = HOLD;
|
||||
}
|
||||
|
||||
void rainbow(uint8_t wait) {
|
||||
uint16_t i, j;
|
||||
|
||||
for (j = 0; j < 256; j++) {
|
||||
for (i = 0; i < strip.numPixels(); i++) {
|
||||
strip.setPixelColor(i, Wheel((i + j) & 255));
|
||||
}
|
||||
strip.show();
|
||||
|
||||
checkForRequests();
|
||||
if (exit_func) {
|
||||
exit_func = false;
|
||||
return;
|
||||
}
|
||||
|
||||
delay(wait);
|
||||
}
|
||||
}
|
||||
|
||||
// Slightly different, this makes the rainbow equally distributed throughout
|
||||
void rainbowCycle(uint8_t wait) {
|
||||
uint16_t i, j;
|
||||
|
||||
for (j = 0; j < 256; j++) { // 1 cycle of all colors on wheel
|
||||
for (i = 0; i < strip.numPixels(); i++) {
|
||||
strip.setPixelColor(i, Wheel(((i * 256 / strip.numPixels()) + j) & 255));
|
||||
}
|
||||
strip.show();
|
||||
|
||||
checkForRequests();
|
||||
if (exit_func) {
|
||||
exit_func = false;
|
||||
return;
|
||||
}
|
||||
|
||||
delay(wait);
|
||||
}
|
||||
}
|
||||
|
||||
// Theatre-style crawling lights.
|
||||
void theaterChase(uint32_t c, uint8_t wait) {
|
||||
for (int q = 0; q < 3; q++) {
|
||||
for (int i = 0; i < strip.numPixels(); i = i + 3) {
|
||||
strip.setPixelColor(i + q, c); //turn every third pixel on
|
||||
}
|
||||
strip.show();
|
||||
|
||||
checkForRequests();
|
||||
if (exit_func) {
|
||||
exit_func = false;
|
||||
return;
|
||||
}
|
||||
delay(wait);
|
||||
|
||||
for (int i = 0; i < strip.numPixels(); i = i + 3) {
|
||||
strip.setPixelColor(i + q, 0); //turn every third pixel off
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Theatre-style crawling lights with rainbow effect
|
||||
void theaterChaseRainbow(uint8_t wait) {
|
||||
for (int j = 0; j < 256; j++) { // cycle all 256 colors in the wheel
|
||||
for (int q = 0; q < 3; q++) {
|
||||
for (int i = 0; i < strip.numPixels(); i = i + 3) {
|
||||
strip.setPixelColor(i + q, Wheel( (i + j) % 255)); //turn every third pixel on
|
||||
}
|
||||
strip.show();
|
||||
|
||||
checkForRequests();
|
||||
if (exit_func) {
|
||||
exit_func = false;
|
||||
return;
|
||||
}
|
||||
delay(wait);
|
||||
|
||||
for (int i = 0; i < strip.numPixels(); i = i + 3) {
|
||||
strip.setPixelColor(i + q, 0); //turn every third pixel off
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
@@ -0,0 +1,97 @@
|
||||
<!--
|
||||
FSWebServer - Example Index Page
|
||||
Copyright (c) 2015 Hristo Gochkov. All rights reserved.
|
||||
This file is part of the ESP8266WebServer library for Arduino environment.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-type" content="text/html; charset=utf-8">
|
||||
<title>ESP Monitor</title>
|
||||
<script type="text/javascript" src="graphs.js"></script>
|
||||
<script type="text/javascript">
|
||||
var heap,temp,digi;
|
||||
var reloadPeriod = 1000;
|
||||
var running = false;
|
||||
|
||||
function loadValues(){
|
||||
if(!running) return;
|
||||
var xh = new XMLHttpRequest();
|
||||
xh.onreadystatechange = function(){
|
||||
if (xh.readyState == 4){
|
||||
if(xh.status == 200) {
|
||||
var res = JSON.parse(xh.responseText);
|
||||
heap.add(res.heap);
|
||||
temp.add(res.analog);
|
||||
digi.add(res.gpio);
|
||||
if(running) setTimeout(loadValues, reloadPeriod);
|
||||
} else running = false;
|
||||
}
|
||||
};
|
||||
xh.open("GET", "/status", true);
|
||||
xh.send(null);
|
||||
};
|
||||
|
||||
function run(){
|
||||
if(!running){
|
||||
running = true;
|
||||
loadValues();
|
||||
}
|
||||
}
|
||||
|
||||
function onBodyLoad(){
|
||||
var refreshInput = document.getElementById("refresh-rate");
|
||||
refreshInput.value = reloadPeriod;
|
||||
refreshInput.onchange = function(e){
|
||||
var value = parseInt(e.target.value);
|
||||
reloadPeriod = (value > 0)?value:0;
|
||||
e.target.value = reloadPeriod;
|
||||
}
|
||||
var stopButton = document.getElementById("stop-button");
|
||||
stopButton.onclick = function(e){
|
||||
running = false;
|
||||
}
|
||||
var startButton = document.getElementById("start-button");
|
||||
startButton.onclick = function(e){
|
||||
run();
|
||||
}
|
||||
|
||||
// Example with 10K thermistor
|
||||
//function calcThermistor(v) {
|
||||
// var t = Math.log(((10230000 / v) - 10000));
|
||||
// t = (1/(0.001129148+(0.000234125*t)+(0.0000000876741*t*t*t)))-273.15;
|
||||
// return (t>120)?0:Math.round(t*10)/10;
|
||||
//}
|
||||
//temp = createGraph(document.getElementById("analog"), "Temperature", 100, 128, 10, 40, false, "cyan", calcThermistor);
|
||||
|
||||
temp = createGraph(document.getElementById("analog"), "Analog Input", 100, 128, 0, 1023, false, "cyan");
|
||||
heap = createGraph(document.getElementById("heap"), "Current Heap", 100, 125, 0, 30000, true, "orange");
|
||||
digi = createDigiGraph(document.getElementById("digital"), "GPIO", 100, 146, [0, 4, 5, 16], "gold");
|
||||
run();
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body id="index" style="margin:0; padding:0;" onload="onBodyLoad()">
|
||||
<div id="controls" style="display: block; border: 1px solid rgb(68, 68, 68); padding: 5px; margin: 5px; width: 362px; background-color: rgb(238, 238, 238);">
|
||||
<label>Period (ms):</label>
|
||||
<input type="number" id="refresh-rate"/>
|
||||
<input type="button" id="start-button" value="Start"/>
|
||||
<input type="button" id="stop-button" value="Stop"/>
|
||||
</div>
|
||||
<div id="heap"></div>
|
||||
<div id="analog"></div>
|
||||
<div id="digital"></div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,33 @@
|
||||
// Neopixel
|
||||
#define PIN 5 // PIN where neopixel / WS2811 strip is attached
|
||||
#define NUMLEDS 12 // Number of leds in the strip
|
||||
|
||||
|
||||
#define HOSTNAME "ESP8266_01" // Friedly hostname
|
||||
|
||||
|
||||
// ***************************************************************************
|
||||
// Global variables / definitions
|
||||
// ***************************************************************************
|
||||
#define DBG_OUTPUT_PORT Serial // Set debug output port
|
||||
|
||||
// List of all color modes
|
||||
enum MODE { HOLD, OFF, ALL, WIPE, RAINBOW, RAINBOWCYCLE, THEATERCHASE, THEATERCHASERAINBOW, TV };
|
||||
|
||||
MODE mode = RAINBOWCYCLE; // Standard mode that is active when software starts
|
||||
|
||||
int delay_ms = 50; // Global variable for storing the delay between color changes --> smaller == faster
|
||||
int brightness = 128; // Global variable for storing the brightness (255 == 100%)
|
||||
|
||||
bool exit_func = false; // Global helper variable to get out of the color modes when mode changes
|
||||
|
||||
struct ledstate // Data structure to store a state of a single led
|
||||
{
|
||||
uint8_t red;
|
||||
uint8_t green;
|
||||
uint8_t blue;
|
||||
};
|
||||
|
||||
typedef struct ledstate LEDState; // Define the datatype LEDState
|
||||
LEDState ledstates[NUMLEDS]; // Get an array of led states to store the state of the whole strip
|
||||
LEDState main_color; // Store the "main color" of the strip used in single color modes
|
||||
@@ -0,0 +1,205 @@
|
||||
// ***************************************************************************
|
||||
// Request handlers
|
||||
// ***************************************************************************
|
||||
void getArgs() {
|
||||
main_color.red = server.arg("r").toInt();
|
||||
main_color.green = server.arg("g").toInt();
|
||||
main_color.blue = server.arg("b").toInt();
|
||||
delay_ms = server.arg("d").toInt();
|
||||
|
||||
if (main_color.red > 255) {
|
||||
main_color.red = 255;
|
||||
}
|
||||
if (main_color.green > 255) {
|
||||
main_color.green = 255;
|
||||
}
|
||||
if (main_color.blue > 255) {
|
||||
main_color.blue = 255;
|
||||
}
|
||||
|
||||
if (main_color.red < 0) {
|
||||
main_color.red = 0;
|
||||
}
|
||||
if (main_color.green < 0) {
|
||||
main_color.green = 0;
|
||||
}
|
||||
if (main_color.blue < 0) {
|
||||
main_color.blue = 0;
|
||||
}
|
||||
|
||||
if (server.arg("d") == "") {
|
||||
delay_ms = 20;
|
||||
}
|
||||
|
||||
DBG_OUTPUT_PORT.print("Mode: ");
|
||||
DBG_OUTPUT_PORT.print(mode);
|
||||
DBG_OUTPUT_PORT.print(", Color: ");
|
||||
DBG_OUTPUT_PORT.print(main_color.red);
|
||||
DBG_OUTPUT_PORT.print(", ");
|
||||
DBG_OUTPUT_PORT.print(main_color.green);
|
||||
DBG_OUTPUT_PORT.print(", ");
|
||||
DBG_OUTPUT_PORT.print(main_color.blue);
|
||||
DBG_OUTPUT_PORT.print(", Delay:");
|
||||
DBG_OUTPUT_PORT.print(delay_ms);
|
||||
DBG_OUTPUT_PORT.print(", Brightness:");
|
||||
DBG_OUTPUT_PORT.println(brightness);
|
||||
}
|
||||
|
||||
void handleMinimalUpload() {
|
||||
char temp[1500];
|
||||
int sec = millis() / 1000;
|
||||
int min = sec / 60;
|
||||
int hr = min / 60;
|
||||
|
||||
snprintf ( temp, 1500,
|
||||
"<!DOCTYPE html>\
|
||||
<html>\
|
||||
<head>\
|
||||
<title>ESP8266 Upload</title>\
|
||||
<meta charset=\"utf-8\">\
|
||||
<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\
|
||||
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\
|
||||
</head>\
|
||||
<body>\
|
||||
<form action=\"/edit\" method=\"post\" enctype=\"multipart/form-data\">\
|
||||
<input type=\"file\" name=\"data\">\
|
||||
<input type=\"text\" name=\"path\" value=\"/\">\
|
||||
<button>Upload</button>\
|
||||
</form>\
|
||||
</body>\
|
||||
</html>",
|
||||
hr, min % 60, sec % 60
|
||||
);
|
||||
server.send ( 200, "text/html", temp );
|
||||
}
|
||||
|
||||
void handleNotFound() {
|
||||
String message = "File Not Found\n\n";
|
||||
message += "URI: ";
|
||||
message += server.uri();
|
||||
message += "\nMethod: ";
|
||||
message += ( server.method() == HTTP_GET ) ? "GET" : "POST";
|
||||
message += "\nArguments: ";
|
||||
message += server.args();
|
||||
message += "\n";
|
||||
for ( uint8_t i = 0; i < server.args(); i++ ) {
|
||||
message += " " + server.argName ( i ) + ": " + server.arg ( i ) + "\n";
|
||||
}
|
||||
server.send ( 404, "text/plain", message );
|
||||
}
|
||||
|
||||
void getStatusJSON() {
|
||||
char json[255];
|
||||
snprintf(json, sizeof(json), "{\"mode\":%d, \"delay_ms\":%d, \"brightness\":%d, \"color\":[%d, %d, %d]}", mode, delay_ms, brightness, main_color.red, main_color.green, main_color.blue);
|
||||
server.send ( 200, "application/json", json );
|
||||
}
|
||||
|
||||
void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t lenght) {
|
||||
switch(type) {
|
||||
case WStype_DISCONNECTED:
|
||||
DBG_OUTPUT_PORT.printf("WS: [%u] Disconnected!\n", num);
|
||||
break;
|
||||
|
||||
case WStype_CONNECTED: {
|
||||
IPAddress ip = webSocket.remoteIP(num);
|
||||
DBG_OUTPUT_PORT.printf("WS: [%u] Connected from %d.%d.%d.%d url: %s\n", num, ip[0], ip[1], ip[2], ip[3], payload);
|
||||
|
||||
// send message to client
|
||||
webSocket.sendTXT(num, "Connected");
|
||||
}
|
||||
break;
|
||||
|
||||
case WStype_TEXT:
|
||||
DBG_OUTPUT_PORT.printf("WS: [%u] get Text: %s\n", num, payload);
|
||||
|
||||
// # ==> Set main color
|
||||
if(payload[0] == '#') {
|
||||
// decode rgb data
|
||||
uint32_t rgb = (uint32_t) strtol((const char *) &payload[1], NULL, 16);
|
||||
main_color.red = ((rgb >> 16) & 0xFF);
|
||||
main_color.green = ((rgb >> 8) & 0xFF);
|
||||
main_color.blue = ((rgb >> 0) & 0xFF);
|
||||
DBG_OUTPUT_PORT.printf("Set main color to: [%u] [%u] [%u]\n", main_color.red, main_color.green, main_color.blue);
|
||||
}
|
||||
|
||||
// # ==> Set delay
|
||||
if(payload[0] == '?') {
|
||||
// decode rgb data
|
||||
uint8_t d = (uint8_t) strtol((const char *) &payload[1], NULL, 16);
|
||||
delay_ms = ((d >> 0) & 0xFF);
|
||||
DBG_OUTPUT_PORT.printf("WS: Set delay to: [%u]\n", delay_ms);
|
||||
}
|
||||
|
||||
// * ==> Set main color and light all LEDs (Shortcut)
|
||||
if(payload[0] == '*') {
|
||||
// decode rgb data
|
||||
uint32_t rgb = (uint32_t) strtol((const char *) &payload[1], NULL, 16);
|
||||
|
||||
main_color.red = ((rgb >> 16) & 0xFF);
|
||||
main_color.green = ((rgb >> 8) & 0xFF);
|
||||
main_color.blue = ((rgb >> 0) & 0xFF);
|
||||
|
||||
for (int i = 0; i < strip.numPixels(); i++) {
|
||||
strip.setPixelColor(i, main_color.red, main_color.green, main_color.blue);
|
||||
}
|
||||
strip.show();
|
||||
DBG_OUTPUT_PORT.printf("WS: Set all leds to main color: [%u] [%u] [%u]\n", main_color.red, main_color.green, main_color.blue);
|
||||
mode = HOLD;
|
||||
}
|
||||
|
||||
// ! ==> Set single LED in given color
|
||||
if(payload[0] == '!') {
|
||||
// decode led index
|
||||
uint64_t rgb = (uint64_t) strtol((const char *) &payload[1], NULL, 16);
|
||||
|
||||
uint8_t led = ((rgb >> 24) & 0xFF);
|
||||
if (led < strip.numPixels()) {
|
||||
ledstates[led].red = ((rgb >> 16) & 0xFF);
|
||||
ledstates[led].green = ((rgb >> 8) & 0xFF);
|
||||
ledstates[led].blue = ((rgb >> 0) & 0xFF);
|
||||
DBG_OUTPUT_PORT.printf("WS: Set single led [%u] to [%u] [%u] [%u]!\n", led, ledstates[led].red, ledstates[led].green, ledstates[led].blue);
|
||||
|
||||
for (uint8_t i = 0; i < strip.numPixels(); i++) {
|
||||
strip.setPixelColor(i, ledstates[i].red, ledstates[i].green, ledstates[i].blue);
|
||||
//DBG_OUTPUT_PORT.printf("[%u]--[%u] [%u] [%u] [%u] LED index!\n", rgb, i, ledstates[i].red, ledstates[i].green, ledstates[i].blue);
|
||||
}
|
||||
strip.show();
|
||||
}
|
||||
mode = HOLD;
|
||||
}
|
||||
|
||||
// ! ==> Activate mode
|
||||
if(payload[0] == '=') {
|
||||
// we get mode data
|
||||
String str_mode = String((char *) &payload[0]);
|
||||
|
||||
exit_func = true;
|
||||
if (str_mode.startsWith("=wipe")) {
|
||||
mode = WIPE;
|
||||
}
|
||||
if (str_mode.startsWith("=rainbow")) {
|
||||
mode = RAINBOW;
|
||||
}
|
||||
if (str_mode.startsWith("=rainbowCycle")) {
|
||||
mode = RAINBOWCYCLE;
|
||||
}
|
||||
if (str_mode.startsWith("=theaterchase")) {
|
||||
mode = THEATERCHASE;
|
||||
}
|
||||
if (str_mode.startsWith("=theaterchaseRainbow")) {
|
||||
mode = THEATERCHASERAINBOW;
|
||||
}
|
||||
if (str_mode.startsWith("=tv")) {
|
||||
mode = TV;
|
||||
}
|
||||
|
||||
DBG_OUTPUT_PORT.printf("Activated mode [%u]!\n", mode);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void checkForRequests() {
|
||||
webSocket.loop();
|
||||
server.handleClient();
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
// ***************************************************************************
|
||||
// SPIFFS Webserver
|
||||
// Source: https://github.com/esp8266/Arduino/tree/master/libraries/ESP8266WebServer/examples/FSBrowser
|
||||
// ***************************************************************************
|
||||
|
||||
/*
|
||||
FSWebServer - Example WebServer with SPIFFS backend for esp8266
|
||||
Copyright (c) 2015 Hristo Gochkov. All rights reserved.
|
||||
This file is part of the ESP8266WebServer library for Arduino environment.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
upload the contents of the data folder with MkSPIFFS Tool ("ESP8266 Sketch Data Upload" in Tools menu in Arduino IDE)
|
||||
or you can upload the contents of a folder if you CD in that folder and run the following command:
|
||||
for file in `ls -A1`; do curl -F "file=@$PWD/$file" esp8266fs.local/edit; done
|
||||
|
||||
access the sample web page at http://esp8266fs.local
|
||||
edit the page by going to http://esp8266fs.local/edit
|
||||
*/
|
||||
|
||||
File fsUploadFile;
|
||||
|
||||
//format bytes
|
||||
String formatBytes(size_t bytes) {
|
||||
if (bytes < 1024) {
|
||||
return String(bytes) + "B";
|
||||
} else if (bytes < (1024 * 1024)) {
|
||||
return String(bytes / 1024.0) + "KB";
|
||||
} else if (bytes < (1024 * 1024 * 1024)) {
|
||||
return String(bytes / 1024.0 / 1024.0) + "MB";
|
||||
} else {
|
||||
return String(bytes / 1024.0 / 1024.0 / 1024.0) + "GB";
|
||||
}
|
||||
}
|
||||
|
||||
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(".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";
|
||||
}
|
||||
|
||||
bool handleFileRead(String path) {
|
||||
DBG_OUTPUT_PORT.println("handleFileRead: " + path);
|
||||
if (path.endsWith("/")) path += "index.htm";
|
||||
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;
|
||||
}
|
||||
|
||||
void handleFileUpload() {
|
||||
if (server.uri() != "/edit") return;
|
||||
HTTPUpload& upload = server.upload();
|
||||
if (upload.status == UPLOAD_FILE_START) {
|
||||
String filename = upload.filename;
|
||||
if (!filename.startsWith("/")) filename = "/" + filename;
|
||||
DBG_OUTPUT_PORT.print("handleFileUpload Name: ");
|
||||
DBG_OUTPUT_PORT.println(filename);
|
||||
fsUploadFile = SPIFFS.open(filename, "w");
|
||||
filename = String();
|
||||
} else if (upload.status == UPLOAD_FILE_WRITE) {
|
||||
//DBG_OUTPUT_PORT.print("handleFileUpload Data: "); DBG_OUTPUT_PORT.println(upload.currentSize);
|
||||
if (fsUploadFile)
|
||||
fsUploadFile.write(upload.buf, upload.currentSize);
|
||||
} else if (upload.status == UPLOAD_FILE_END) {
|
||||
if (fsUploadFile)
|
||||
fsUploadFile.close();
|
||||
DBG_OUTPUT_PORT.print("handleFileUpload Size: "); DBG_OUTPUT_PORT.println(upload.totalSize);
|
||||
}
|
||||
}
|
||||
|
||||
void handleFileDelete() {
|
||||
if (server.args() == 0) return server.send(500, "text/plain", "BAD ARGS");
|
||||
String path = server.arg(0);
|
||||
DBG_OUTPUT_PORT.println("handleFileDelete: " + path);
|
||||
if (path == "/")
|
||||
return server.send(500, "text/plain", "BAD PATH");
|
||||
if (!SPIFFS.exists(path))
|
||||
return server.send(404, "text/plain", "FileNotFound");
|
||||
SPIFFS.remove(path);
|
||||
server.send(200, "text/plain", "");
|
||||
path = String();
|
||||
}
|
||||
|
||||
void handleFileCreate() {
|
||||
if (server.args() == 0)
|
||||
return server.send(500, "text/plain", "BAD ARGS");
|
||||
String path = server.arg(0);
|
||||
DBG_OUTPUT_PORT.println("handleFileCreate: " + path);
|
||||
if (path == "/")
|
||||
return server.send(500, "text/plain", "BAD PATH");
|
||||
if (SPIFFS.exists(path))
|
||||
return server.send(500, "text/plain", "FILE EXISTS");
|
||||
File file = SPIFFS.open(path, "w");
|
||||
if (file)
|
||||
file.close();
|
||||
else
|
||||
return server.send(500, "text/plain", "CREATE FAILED");
|
||||
server.send(200, "text/plain", "");
|
||||
path = String();
|
||||
}
|
||||
|
||||
void handleFileList() {
|
||||
if (!server.hasArg("dir")) {
|
||||
server.send(500, "text/plain", "BAD ARGS");
|
||||
return;
|
||||
}
|
||||
|
||||
String path = server.arg("dir");
|
||||
DBG_OUTPUT_PORT.println("handleFileList: " + path);
|
||||
Dir dir = SPIFFS.openDir(path);
|
||||
path = String();
|
||||
|
||||
String output = "[";
|
||||
while (dir.next()) {
|
||||
File entry = dir.openFile("r");
|
||||
if (output != "[") output += ',';
|
||||
bool isDir = false;
|
||||
output += "{\"type\":\"";
|
||||
output += (isDir) ? "dir" : "file";
|
||||
output += "\",\"name\":\"";
|
||||
output += String(entry.name()).substring(1);
|
||||
output += "\"}";
|
||||
entry.close();
|
||||
}
|
||||
|
||||
output += "]";
|
||||
server.send(200, "text/json", output);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user