first
This commit is contained in:
commit
7ec31edf21
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
src/secrets.h
|
||||
.pio
|
||||
.vscode
|
||||
1
data/css/styles.css
Normal file
1
data/css/styles.css
Normal file
@ -0,0 +1 @@
|
||||
body { padding-bottom: 70px; }
|
||||
BIN
data/favicon.ico
Normal file
BIN
data/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
BIN
data/images/atom196.png
Normal file
BIN
data/images/atom196.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.3 KiB |
232
data/index.htm
Normal file
232
data/index.htm
Normal file
@ -0,0 +1,232 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>ESP32 FastLED Web Server by Evil Genius Labs</title>
|
||||
|
||||
<!-- request CSS from internet CDN -->
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous" />
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jquery-minicolors/2.2.4/jquery.minicolors.min.css" integrity="sha256-4wnSkPYU5B4yngAlx/rEb8LdfMah4teUth4AfhGEuaY=" crossorigin="anonymous" />
|
||||
|
||||
<!-- request CSS from the ESP32 web server -->
|
||||
<!-- <link rel="stylesheet" href="css/bootstrap.min.css"> -->
|
||||
<!-- <link rel="stylesheet" href="css/jquery.minicolors.min.css"> -->
|
||||
|
||||
<!-- <link rel="stylesheet" href="/css/styles.css" /> -->
|
||||
|
||||
<link rel="icon" href="images/atom196.png" />
|
||||
</head>
|
||||
|
||||
<body style="padding-bottom: 70px;">
|
||||
|
||||
<nav class="navbar navbar-default navbar-static-top" id="top" role="banner">
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar-collapse-1" aria-expanded="false">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
<a class="navbar-brand" href="https://www.evilgeniuslabs.org" target="_blank"><img src="https://evilgeniuslabs.org/images/atom.svg" style="width: 24px; height: 24px;" /></a>
|
||||
<a class="navbar-brand" href="https://www.evilgeniuslabs.org" target="_blank">Evil Genius Labs</a>
|
||||
</div>
|
||||
<div class="collapse navbar-collapse" id="navbar-collapse-1">
|
||||
<ul class="nav navbar-nav">
|
||||
<li class="active"><a href="/">ESP32 FastLED Web Server <span class="sr-only">(current)</span></a></li>
|
||||
<!-- <li><a href="/simple.htm" target="_blank" title="Simple Mode">Simple</a></li>
|
||||
<li><a href="/edit.htm" target="_blank" title="Edit Files">Files</a></li>
|
||||
<li><a href="/update" target="_blank" title="Update Firmware">Firmware</a></li> -->
|
||||
</ul>
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li>
|
||||
<a href="https://github.com/jasoncoon/esp32-fastled-webserver">
|
||||
<img style="height: 16px;" src="https://assets-cdn.github.com/favicon.ico" />
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<div id="container" class="container">
|
||||
|
||||
<form class="form-horizontal" id="form">
|
||||
</form>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="templates" style="display: none">
|
||||
|
||||
<div id="sectionTemplate" class="form-group">
|
||||
<div class="col-sm-12">
|
||||
<hr style="margin-bottom: 5px;margin-top: 5px;" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="numberTemplate" class="form-group">
|
||||
<label class="col-sm-2 control-label"></label>
|
||||
<div class="col-sm-2">
|
||||
<input class="form-control input" type="number" step="1" min="0" max="255" />
|
||||
</div>
|
||||
<div class="col-sm-8">
|
||||
<input class="form-control slider" type="range" step="1" min="0" max="255" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="booleanTemplate" class="form-group">
|
||||
<label class="col-sm-2 control-label"></label>
|
||||
<div class="col-sm-10">
|
||||
<div class="btn-group" role="group">
|
||||
<button type="button" class="btn btn-default" id="btnOn">On</button>
|
||||
<button type="button" class="btn btn-default" id="btnOff">Off</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="selectTemplate" class="form-group">
|
||||
<label class="col-sm-2 control-label"></label>
|
||||
<div class="col-sm-8">
|
||||
<select class="form-control"></select>
|
||||
</div>
|
||||
<div class="col-sm-2">
|
||||
<div class="btn-group" role="group" aria-label="...">
|
||||
<button type="button" class="btn btn-default btn-previous"
|
||||
aria-label="Previous" title="Previous">
|
||||
<span class="glyphicon glyphicon-chevron-left"></span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-default btn-next"
|
||||
aria-label="Next" title="Next">
|
||||
<span class="glyphicon glyphicon-chevron-right"></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="colorPaletteTemplate" class="form-group">
|
||||
<label class="col-sm-2 control-label color-label"></label>
|
||||
<div class="col-sm-10">
|
||||
<div class="btn-group btn-group-justified" role="group">
|
||||
<div class="btn-group" role="group">
|
||||
<button type="button" class="btn btn-default btn-color" style="background: #FF0000;" title="Red"> </button>
|
||||
</div>
|
||||
<div class="btn-group" role="group">
|
||||
<button type="button" class="btn btn-default btn-color" style="background: #FF8000;" title="Orange"> </button>
|
||||
</div>
|
||||
<div class="btn-group" role="group">
|
||||
<button type="button" class="btn btn-default btn-color" style="background: #FFFF00;" title="Yellow"> </button>
|
||||
</div>
|
||||
<div class="btn-group" role="group">
|
||||
<button type="button" class="btn btn-default btn-color" style="background: #80FF00;" title="Chartreuse"> </button>
|
||||
</div>
|
||||
<div class="btn-group" role="group">
|
||||
<button type="button" class="btn btn-default btn-color" style="background: #00FF00;" title="Green"> </button>
|
||||
</div>
|
||||
<div class="btn-group" role="group">
|
||||
<button type="button" class="btn btn-default btn-color" style="background: #00FF80;" title="Spring Green"> </button>
|
||||
</div>
|
||||
<div class="btn-group" role="group">
|
||||
<button type="button" class="btn btn-default btn-color" style="background: #00FFFF;" title="Cyan"> </button>
|
||||
</div>
|
||||
<div class="btn-group" role="group">
|
||||
<button type="button" class="btn btn-default btn-color" style="background: #0080FF;" title="Azure"> </button>
|
||||
</div>
|
||||
<div class="btn-group" role="group">
|
||||
<button type="button" class="btn btn-default btn-color" style="background: #0000FF;" title="Blue"> </button>
|
||||
</div>
|
||||
<div class="btn-group" role="group">
|
||||
<button type="button" class="btn btn-default btn-color" style="background: #8000FF;" title="Violet"> </button>
|
||||
</div>
|
||||
<div class="btn-group" role="group">
|
||||
<button type="button" class="btn btn-default btn-color" style="background: #FF00FF;" title="Magenta"> </button>
|
||||
</div>
|
||||
<div class="btn-group" role="group">
|
||||
<button type="button" class="btn btn-default btn-color" style="background: #FF0080;" title="Rose"> </button>
|
||||
</div>
|
||||
<div class="btn-group" role="group">
|
||||
<button type="button" class="btn btn-default btn-color" style="background: #FFFFFF;" title="White"> </button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="colorTemplate">
|
||||
<div class="form-group">
|
||||
<!-- <label class="col-sm-2 control-label color-label"></label> -->
|
||||
<div class="col-sm-12 col-sm-offset-2">
|
||||
<input type="text" class="form-control minicolors" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label">Red</label>
|
||||
<div class="col-sm-2">
|
||||
<input class="form-control color-red-input" type="number" step="1" min="0" max="255" />
|
||||
</div>
|
||||
<div class="col-sm-8">
|
||||
<input class="form-control color-red-slider" type="range" step="1" min="0" max="255" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label">Green</label>
|
||||
<div class="col-sm-2">
|
||||
<input class="form-control color-green-input" type="number" step="1" min="0" max="255" />
|
||||
</div>
|
||||
<div class="col-sm-8">
|
||||
<input class="form-control color-green-slider" type="range" step="1" min="0" max="255" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-2 control-label">Blue</label>
|
||||
<div class="col-sm-2">
|
||||
<input class="form-control color-blue-input" type="number" step="1" min="0" max="255" />
|
||||
</div>
|
||||
<div class="col-sm-8">
|
||||
<input class="form-control color-blue-slider" type="range" step="1" min="0" max="255" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<nav class="navbar navbar-default navbar-fixed-bottom">
|
||||
<div class="container">
|
||||
<div class="navbar-header">
|
||||
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar-collapse-2" aria-expanded="false">
|
||||
<span class="sr-only">Toggle navigation</span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
<span class="icon-bar"></span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="collapse navbar-collapse" id="navbar-collapse-2">
|
||||
<ul class="nav navbar-nav">
|
||||
<li>
|
||||
<a href="/" aria-label="Refresh" title="Refresh">
|
||||
<span class="glyphicon glyphicon-refresh" id="btnRefresh"></span>
|
||||
</a>
|
||||
</li>
|
||||
<li><p class="navbar-text" id="status">Loading, please wait...</p></li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
<!-- request js from internet CDN -->
|
||||
<script src="https://code.jquery.com/jquery-3.1.1.min.js" integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8=" crossorigin="anonymous"></script>
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-minicolors/2.2.4/jquery.minicolors.min.js" integrity="sha256-XAFQ9dZ6hy8p/GRhU8h/8pMvM1etymiJLZW1CiHV3bQ=" crossorigin="anonymous"></script>
|
||||
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/reconnecting-websocket/1.0.0/reconnecting-websocket.min.js" integrity="sha256-A4JwlcDvqO4JXpvEtvWY1RH8JAEMu5W21wP8GUXLUNs=" crossorigin="anonymous"></script> -->
|
||||
|
||||
<!-- request js from the ESP32 web server -->
|
||||
<!-- <script src="js/jquery-3.1.1.min.js"></script> -->
|
||||
<!-- <script src="js/bootstrap.min.js"></script> -->
|
||||
<!-- <script src="js/jquery.minicolors.min.js"></script> -->
|
||||
<!-- <script src="js/r-websocket.min.js"></script> -->
|
||||
|
||||
<script src="js/app.js"></script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
467
data/js/app.js
Normal file
467
data/js/app.js
Normal file
@ -0,0 +1,467 @@
|
||||
// used when hosting the site on the ESP8266
|
||||
var address = location.hostname;
|
||||
var urlBase = "";
|
||||
|
||||
// used when hosting the site somewhere other than the ESP8266 (handy for testing without waiting forever to upload to SPIFFS)
|
||||
// var address = "192.168.86.55";
|
||||
// var urlBase = "http://" + address + "/";
|
||||
|
||||
var postColorTimer = {};
|
||||
var postValueTimer = {};
|
||||
|
||||
var ignoreColorChange = false;
|
||||
|
||||
// var ws = new ReconnectingWebSocket('ws://' + address + ':81/', ['arduino']);
|
||||
// ws.debug = true;
|
||||
//
|
||||
// ws.onmessage = function(evt) {
|
||||
// if(evt.data != null)
|
||||
// {
|
||||
// var data = JSON.parse(evt.data);
|
||||
// if(data == null) return;
|
||||
// updateFieldValue(data.name, data.value);
|
||||
// }
|
||||
// }
|
||||
|
||||
$(document).ready(function() {
|
||||
$("#status").html("Connecting, please wait...");
|
||||
|
||||
$.get(urlBase + "all", function(data) {
|
||||
$("#status").html("Loading, please wait...");
|
||||
|
||||
$.each(data, function(index, field) {
|
||||
if (field.type == "Number") {
|
||||
addNumberField(field);
|
||||
} else if (field.type == "Boolean") {
|
||||
addBooleanField(field);
|
||||
} else if (field.type == "Select") {
|
||||
addSelectField(field);
|
||||
} else if (field.type == "Color") {
|
||||
addColorFieldPalette(field);
|
||||
addColorFieldPicker(field);
|
||||
} else if (field.type == "Section") {
|
||||
addSectionField(field);
|
||||
}
|
||||
});
|
||||
|
||||
$(".minicolors").minicolors({
|
||||
theme: "bootstrap",
|
||||
changeDelay: 200,
|
||||
control: "wheel",
|
||||
format: "rgb",
|
||||
inline: true
|
||||
});
|
||||
|
||||
$("#status").html("Ready");
|
||||
})
|
||||
.fail(function(errorThrown) {
|
||||
console.log("error: " + errorThrown);
|
||||
});
|
||||
});
|
||||
|
||||
function addNumberField(field) {
|
||||
var template = $("#numberTemplate").clone();
|
||||
|
||||
template.attr("id", "form-group-" + field.name);
|
||||
template.attr("data-field-type", field.type);
|
||||
|
||||
var label = template.find(".control-label");
|
||||
label.attr("for", "input-" + field.name);
|
||||
label.text(field.label);
|
||||
|
||||
var input = template.find(".input");
|
||||
var slider = template.find(".slider");
|
||||
slider.attr("id", "input-" + field.name);
|
||||
if (field.min) {
|
||||
input.attr("min", field.min);
|
||||
slider.attr("min", field.min);
|
||||
}
|
||||
if (field.max) {
|
||||
input.attr("max", field.max);
|
||||
slider.attr("max", field.max);
|
||||
}
|
||||
if (field.step) {
|
||||
input.attr("step", field.step);
|
||||
slider.attr("step", field.step);
|
||||
}
|
||||
input.val(field.value);
|
||||
slider.val(field.value);
|
||||
|
||||
slider.on("change mousemove", function() {
|
||||
input.val($(this).val());
|
||||
});
|
||||
|
||||
slider.on("change", function() {
|
||||
var value = $(this).val();
|
||||
input.val(value);
|
||||
field.value = value;
|
||||
delayPostValue(field.name, value);
|
||||
});
|
||||
|
||||
input.on("change", function() {
|
||||
var value = $(this).val();
|
||||
slider.val(value);
|
||||
field.value = value;
|
||||
delayPostValue(field.name, value);
|
||||
});
|
||||
|
||||
$("#form").append(template);
|
||||
}
|
||||
|
||||
function addBooleanField(field) {
|
||||
var template = $("#booleanTemplate").clone();
|
||||
|
||||
template.attr("id", "form-group-" + field.name);
|
||||
template.attr("data-field-type", field.type);
|
||||
|
||||
var label = template.find(".control-label");
|
||||
label.attr("for", "btn-group-" + field.name);
|
||||
label.text(field.label);
|
||||
|
||||
var btngroup = template.find(".btn-group");
|
||||
btngroup.attr("id", "btn-group-" + field.name);
|
||||
|
||||
var btnOn = template.find("#btnOn");
|
||||
var btnOff = template.find("#btnOff");
|
||||
|
||||
btnOn.attr("id", "btnOn" + field.name);
|
||||
btnOff.attr("id", "btnOff" + field.name);
|
||||
|
||||
btnOn.attr("class", field.value ? "btn btn-primary" : "btn btn-default");
|
||||
btnOff.attr("class", !field.value ? "btn btn-primary" : "btn btn-default");
|
||||
|
||||
btnOn.click(function() {
|
||||
setBooleanFieldValue(field, btnOn, btnOff, 1)
|
||||
});
|
||||
btnOff.click(function() {
|
||||
setBooleanFieldValue(field, btnOn, btnOff, 0)
|
||||
});
|
||||
|
||||
$("#form").append(template);
|
||||
}
|
||||
|
||||
function addSelectField(field) {
|
||||
var template = $("#selectTemplate").clone();
|
||||
|
||||
template.attr("id", "form-group-" + field.name);
|
||||
template.attr("data-field-type", field.type);
|
||||
|
||||
var id = "input-" + field.name;
|
||||
|
||||
var label = template.find(".control-label");
|
||||
label.attr("for", id);
|
||||
label.text(field.label);
|
||||
|
||||
var select = template.find(".form-control");
|
||||
select.attr("id", id);
|
||||
|
||||
for (var i = 0; i < field.options.length; i++) {
|
||||
var optionText = field.options[i];
|
||||
var option = $("<option></option>");
|
||||
option.text(optionText);
|
||||
option.attr("value", i);
|
||||
select.append(option);
|
||||
}
|
||||
|
||||
select.val(field.value);
|
||||
|
||||
select.change(function() {
|
||||
var value = template.find("#" + id + " option:selected").index();
|
||||
postValue(field.name, value);
|
||||
});
|
||||
|
||||
var previousButton = template.find(".btn-previous");
|
||||
var nextButton = template.find(".btn-next");
|
||||
|
||||
previousButton.click(function() {
|
||||
var value = template.find("#" + id + " option:selected").index();
|
||||
var count = select.find("option").length;
|
||||
value--;
|
||||
if(value < 0)
|
||||
value = count - 1;
|
||||
select.val(value);
|
||||
postValue(field.name, value);
|
||||
});
|
||||
|
||||
nextButton.click(function() {
|
||||
var value = template.find("#" + id + " option:selected").index();
|
||||
var count = select.find("option").length;
|
||||
value++;
|
||||
if(value >= count)
|
||||
value = 0;
|
||||
select.val(value);
|
||||
postValue(field.name, value);
|
||||
});
|
||||
|
||||
$("#form").append(template);
|
||||
}
|
||||
|
||||
function addColorFieldPicker(field) {
|
||||
var template = $("#colorTemplate").clone();
|
||||
|
||||
template.attr("id", "form-group-" + field.name);
|
||||
template.attr("data-field-type", field.type);
|
||||
|
||||
var id = "input-" + field.name;
|
||||
|
||||
var input = template.find(".minicolors");
|
||||
input.attr("id", id);
|
||||
|
||||
if(!field.value.startsWith("rgb("))
|
||||
field.value = "rgb(" + field.value;
|
||||
|
||||
if(!field.value.endsWith(")"))
|
||||
field.value += ")";
|
||||
|
||||
input.val(field.value);
|
||||
|
||||
var components = rgbToComponents(field.value);
|
||||
|
||||
var redInput = template.find(".color-red-input");
|
||||
var greenInput = template.find(".color-green-input");
|
||||
var blueInput = template.find(".color-blue-input");
|
||||
|
||||
var redSlider = template.find(".color-red-slider");
|
||||
var greenSlider = template.find(".color-green-slider");
|
||||
var blueSlider = template.find(".color-blue-slider");
|
||||
|
||||
redInput.attr("id", id + "-red");
|
||||
greenInput.attr("id", id + "-green");
|
||||
blueInput.attr("id", id + "-blue");
|
||||
|
||||
redSlider.attr("id", id + "-red-slider");
|
||||
greenSlider.attr("id", id + "-green-slider");
|
||||
blueSlider.attr("id", id + "-blue-slider");
|
||||
|
||||
redInput.val(components.r);
|
||||
greenInput.val(components.g);
|
||||
blueInput.val(components.b);
|
||||
|
||||
redSlider.val(components.r);
|
||||
greenSlider.val(components.g);
|
||||
blueSlider.val(components.b);
|
||||
|
||||
redInput.on("change", function() {
|
||||
var value = $("#" + id).val();
|
||||
var r = $(this).val();
|
||||
var components = rgbToComponents(value);
|
||||
field.value = r + "," + components.g + "," + components.b;
|
||||
$("#" + id).minicolors("value", "rgb(" + field.value + ")");
|
||||
redSlider.val(r);
|
||||
});
|
||||
|
||||
greenInput.on("change", function() {
|
||||
var value = $("#" + id).val();
|
||||
var g = $(this).val();
|
||||
var components = rgbToComponents(value);
|
||||
field.value = components.r + "," + g + "," + components.b;
|
||||
$("#" + id).minicolors("value", "rgb(" + field.value + ")");
|
||||
greenSlider.val(g);
|
||||
});
|
||||
|
||||
blueInput.on("change", function() {
|
||||
var value = $("#" + id).val();
|
||||
var b = $(this).val();
|
||||
var components = rgbToComponents(value);
|
||||
field.value = components.r + "," + components.g + "," + b;
|
||||
$("#" + id).minicolors("value", "rgb(" + field.value + ")");
|
||||
blueSlider.val(b);
|
||||
});
|
||||
|
||||
redSlider.on("change", function() {
|
||||
var value = $("#" + id).val();
|
||||
var r = $(this).val();
|
||||
var components = rgbToComponents(value);
|
||||
field.value = r + "," + components.g + "," + components.b;
|
||||
$("#" + id).minicolors("value", "rgb(" + field.value + ")");
|
||||
redInput.val(r);
|
||||
});
|
||||
|
||||
greenSlider.on("change", function() {
|
||||
var value = $("#" + id).val();
|
||||
var g = $(this).val();
|
||||
var components = rgbToComponents(value);
|
||||
field.value = components.r + "," + g + "," + components.b;
|
||||
$("#" + id).minicolors("value", "rgb(" + field.value + ")");
|
||||
greenInput.val(g);
|
||||
});
|
||||
|
||||
blueSlider.on("change", function() {
|
||||
var value = $("#" + id).val();
|
||||
var b = $(this).val();
|
||||
var components = rgbToComponents(value);
|
||||
field.value = components.r + "," + components.g + "," + b;
|
||||
$("#" + id).minicolors("value", "rgb(" + field.value + ")");
|
||||
blueInput.val(b);
|
||||
});
|
||||
|
||||
redSlider.on("change mousemove", function() {
|
||||
redInput.val($(this).val());
|
||||
});
|
||||
|
||||
greenSlider.on("change mousemove", function() {
|
||||
greenInput.val($(this).val());
|
||||
});
|
||||
|
||||
blueSlider.on("change mousemove", function() {
|
||||
blueInput.val($(this).val());
|
||||
});
|
||||
|
||||
input.on("change", function() {
|
||||
if (ignoreColorChange) return;
|
||||
|
||||
var value = $(this).val();
|
||||
var components = rgbToComponents(value);
|
||||
|
||||
redInput.val(components.r);
|
||||
greenInput.val(components.g);
|
||||
blueInput.val(components.b);
|
||||
|
||||
redSlider.val(components.r);
|
||||
greenSlider.val(components.g);
|
||||
blueSlider.val(components.b);
|
||||
|
||||
field.value = components.r + "," + components.g + "," + components.b;
|
||||
delayPostColor(field.name, components);
|
||||
});
|
||||
|
||||
$("#form").append(template);
|
||||
}
|
||||
|
||||
function addColorFieldPalette(field) {
|
||||
var template = $("#colorPaletteTemplate").clone();
|
||||
|
||||
var buttons = template.find(".btn-color");
|
||||
|
||||
var label = template.find(".control-label");
|
||||
label.text(field.label);
|
||||
|
||||
buttons.each(function(index, button) {
|
||||
$(button).click(function() {
|
||||
var rgb = $(this).css('backgroundColor');
|
||||
var components = rgbToComponents(rgb);
|
||||
|
||||
field.value = components.r + "," + components.g + "," + components.b;
|
||||
postColor(field.name, components);
|
||||
|
||||
ignoreColorChange = true;
|
||||
var id = "#input-" + field.name;
|
||||
$(id).minicolors("value", "rgb(" + field.value + ")");
|
||||
$(id + "-red").val(components.r);
|
||||
$(id + "-green").val(components.g);
|
||||
$(id + "-blue").val(components.b);
|
||||
$(id + "-red-slider").val(components.r);
|
||||
$(id + "-green-slider").val(components.g);
|
||||
$(id + "-blue-slider").val(components.b);
|
||||
ignoreColorChange = false;
|
||||
});
|
||||
});
|
||||
|
||||
$("#form").append(template);
|
||||
}
|
||||
|
||||
function addSectionField(field) {
|
||||
var template = $("#sectionTemplate").clone();
|
||||
|
||||
template.attr("id", "form-group-section-" + field.name);
|
||||
template.attr("data-field-type", field.type);
|
||||
|
||||
$("#form").append(template);
|
||||
}
|
||||
|
||||
function updateFieldValue(name, value) {
|
||||
var group = $("#form-group-" + name);
|
||||
|
||||
var type = group.attr("data-field-type");
|
||||
|
||||
if (type == "Number") {
|
||||
var input = group.find(".form-control");
|
||||
input.val(value);
|
||||
} else if (type == "Boolean") {
|
||||
var btnOn = group.find("#btnOn" + name);
|
||||
var btnOff = group.find("#btnOff" + name);
|
||||
|
||||
btnOn.attr("class", value ? "btn btn-primary" : "btn btn-default");
|
||||
btnOff.attr("class", !value ? "btn btn-primary" : "btn btn-default");
|
||||
|
||||
} else if (type == "Select") {
|
||||
var select = group.find(".form-control");
|
||||
select.val(value);
|
||||
} else if (type == "Color") {
|
||||
var input = group.find(".form-control");
|
||||
input.val("rgb(" + value + ")");
|
||||
}
|
||||
};
|
||||
|
||||
function setBooleanFieldValue(field, btnOn, btnOff, value) {
|
||||
field.value = value;
|
||||
|
||||
btnOn.attr("class", field.value ? "btn btn-primary" : "btn btn-default");
|
||||
btnOff.attr("class", !field.value ? "btn btn-primary" : "btn btn-default");
|
||||
|
||||
postValue(field.name, field.value);
|
||||
}
|
||||
|
||||
function postValue(name, value) {
|
||||
$("#status").html("Setting " + name + ": " + value + ", please wait...");
|
||||
|
||||
var body = { name: name, value: value };
|
||||
|
||||
$.post(urlBase + "fieldValue?name=" + name + "&value=" + value, body, function(data) {
|
||||
if (data.name != null) {
|
||||
$("#status").html("Set " + name + ": " + data.name);
|
||||
} else {
|
||||
$("#status").html("Set " + name + ": " + data);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function delayPostValue(name, value) {
|
||||
clearTimeout(postValueTimer);
|
||||
postValueTimer = setTimeout(function() {
|
||||
postValue(name, value);
|
||||
}, 300);
|
||||
}
|
||||
|
||||
function postColor(name, value) {
|
||||
$("#status").html("Setting " + name + ": " + value.r + "," + value.g + "," + value.b + ", please wait...");
|
||||
|
||||
var body = { name: name, r: value.r, g: value.g, b: value.b };
|
||||
|
||||
$.post(urlBase + "fieldValue?name=" + name + "&value=" + "&r=" + value.r + "&g=" + value.g + "&b=" + value.b, body, function(data) {
|
||||
$("#status").html("Set " + name + ": " + data);
|
||||
})
|
||||
.fail(
|
||||
function(jqXHR, textStatus, errorThrown) {
|
||||
console.error(textStatus);
|
||||
console.error(errorThrown);
|
||||
$("#status").html("Fail: " + textStatus + " " + errorThrown);
|
||||
});
|
||||
}
|
||||
|
||||
function delayPostColor(name, value) {
|
||||
clearTimeout(postColorTimer);
|
||||
postColorTimer = setTimeout(function() {
|
||||
postColor(name, value);
|
||||
}, 300);
|
||||
}
|
||||
|
||||
function componentToHex(c) {
|
||||
var hex = c.toString(16);
|
||||
return hex.length == 1 ? "0" + hex : hex;
|
||||
}
|
||||
|
||||
function rgbToHex(r, g, b) {
|
||||
return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b);
|
||||
}
|
||||
|
||||
function rgbToComponents(rgb) {
|
||||
var components = {};
|
||||
|
||||
rgb = rgb.match(/^rgb\((\d+),\s*(\d+),\s*(\d+)\)$/);
|
||||
components.r = parseInt(rgb[1]);
|
||||
components.g = parseInt(rgb[2]);
|
||||
components.b = parseInt(rgb[3]);
|
||||
|
||||
return components;
|
||||
}
|
||||
27
platformio.ini
Normal file
27
platformio.ini
Normal file
@ -0,0 +1,27 @@
|
||||
; PlatformIO Project Configuration File
|
||||
;
|
||||
; Build options: build flags, source filter
|
||||
; Upload options: custom upload port, speed and extra flags
|
||||
; Library options: dependencies, extra library storages
|
||||
; Advanced options: extra scripting
|
||||
;
|
||||
; Please visit documentation for the other options and examples
|
||||
; https://docs.platformio.org/page/projectconf.html
|
||||
|
||||
[env:default]
|
||||
platform = espressif32
|
||||
board = esp32cam
|
||||
framework = arduino
|
||||
monitor_speed = 115200
|
||||
upload_speed = 230400
|
||||
upload_port = /dev/ttyUSB0
|
||||
board_build.flash_mode = qio
|
||||
build_flags =
|
||||
-DCORE_DEBUG_LEVEL=0
|
||||
-DBOARD_HAS_PSRAM
|
||||
-mfix-esp32-psram-cache-issue
|
||||
|
||||
lib_deps =
|
||||
https://github.com/geeksville/Micro-RTSP.git
|
||||
FastLED
|
||||
|
||||
674
src/LICENSE
Normal file
674
src/LICENSE
Normal file
@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Use with the GNU Affero General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU Affero General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU GPL, see
|
||||
<http://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
||||
71
src/README.md
Normal file
71
src/README.md
Normal file
@ -0,0 +1,71 @@
|
||||
# ESP32 FastLED Web Server
|
||||
**Work in progress ESP32 port of https://github.com/jasoncoon/esp8266-fastled-webserver**
|
||||
|
||||
Control addressable LEDs with an ESP32 via a web browser over Wi-Fi.
|
||||
|
||||
## Features
|
||||
### Currently Working:
|
||||
* [x] DemoReel100 patterns
|
||||
* [x] Static web app file serving from SPIFFS
|
||||
* [x] Ability to adjust these settings via the HTTP REST API:
|
||||
* [x] power on/off
|
||||
* [x] brightness
|
||||
* [x] pattern
|
||||
* [x] autoplay on/off
|
||||
* [x] autoplay duration
|
||||
* [x] speed
|
||||
* [x] palette
|
||||
* [x] auto palette cycling
|
||||
* [x] palette duration
|
||||
* [x] solid color
|
||||
* [x] twinkle speed/density
|
||||
* [x] fire cooling/sparking
|
||||
* [x] Setting storage in EEPROM
|
||||
|
||||
### Currently Lacking:
|
||||
* [ ] WebSockets for automatically refreshing/syncing web clients
|
||||
|
||||
## Requirements
|
||||
|
||||
### Hardware
|
||||
|
||||
#### ESP32 Development Board
|
||||
|
||||
[](https://www.adafruit.com/product/3405)
|
||||
|
||||
[Adafruit HUZZAH32 – ESP32 Feather Board](https://www.adafruit.com/product/3405)
|
||||
|
||||
**or**
|
||||
|
||||
[WEMOS LOLIN D32](https://wiki.wemos.cc/products:d32:d32)
|
||||
|
||||
**or**
|
||||
|
||||
[An ESP32 development board of your choice](https://www.google.com/search?q=esp32+development+board)
|
||||
|
||||
#### Addressable LED strip
|
||||
|
||||
[](https://www.adafruit.com/product/1586)
|
||||
|
||||
[Adafruit NeoPixel Ring](https://www.adafruit.com/product/1586)
|
||||
|
||||
#### Other hardware:
|
||||
|
||||
* [3.3V to 5V Logic Level Shifter](http://www.digikey.com/product-detail/en/texas-instruments/SN74HCT245N/296-1612-5-ND/277258) (required if LEDs "glitch")
|
||||
* [Octo Level Shifter FeatherWing](https://www.evilgeniuslabs.org/level-shifter-featherwing) (tidy level shifter PCB)
|
||||
|
||||
Recommended by [Adafruit NeoPixel "Best Practices"](https://learn.adafruit.com/adafruit-neopixel-uberguide/best-practices) to help protect LEDs from current onrush:
|
||||
* [1000µF Capacitor](http://www.digikey.com/product-detail/en/panasonic-electronic-components/ECA-1EM102/P5156-ND/245015)
|
||||
* [300 to 500 Ohm resistor](https://www.digikey.com/product-detail/en/stackpole-electronics-inc/CF14JT470R/CF14JT470RCT-ND/1830342)
|
||||
|
||||
### Software
|
||||
|
||||
* [Arduino](https://www.arduino.cc/en/main/software)
|
||||
* [ESP32 Arduino Libraries & Tools](https://github.com/espressif/arduino-esp32)
|
||||
* [Arduino ESP32 filesystem uploader](https://github.com/me-no-dev/arduino-esp32fs-plugin)
|
||||
|
||||
#### Libraries
|
||||
|
||||
* [FastLED](https://github.com/FastLED/FastLED)
|
||||
* [ESP32 Arduino Libraries & Tools](https://github.com/espressif/arduino-esp32)
|
||||
* [ESP8266/ESP32 WebServer](https://github.com/bbx10/WebServer_tng)
|
||||
209
src/field.h
Normal file
209
src/field.h
Normal file
@ -0,0 +1,209 @@
|
||||
/*
|
||||
ESP32 FastLED WebServer: https://github.com/jasoncoon/esp32-fastled-webserver
|
||||
Copyright (C) 2017 Jason Coon
|
||||
|
||||
Built upon the amazing FastLED work of Daniel Garcia and Mark Kriegsman:
|
||||
https://github.com/FastLED/FastLED
|
||||
|
||||
ESP32 support provided by the hard work of Sam Guyer:
|
||||
https://github.com/samguyer/FastLED
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
typedef String (*FieldSetter)(String);
|
||||
typedef String (*FieldGetter)();
|
||||
|
||||
const String NumberFieldType = "Number";
|
||||
const String BooleanFieldType = "Boolean";
|
||||
const String SelectFieldType = "Select";
|
||||
const String ColorFieldType = "Color";
|
||||
const String SectionFieldType = "Section";
|
||||
|
||||
typedef struct {
|
||||
public:
|
||||
String name;
|
||||
String label;
|
||||
String type;
|
||||
uint8_t min;
|
||||
uint8_t max;
|
||||
FieldGetter getValue;
|
||||
FieldGetter getOptions;
|
||||
FieldSetter setValue;
|
||||
} Field;
|
||||
|
||||
typedef Field FieldList[];
|
||||
|
||||
Field getField(String name, FieldList fields, uint8_t count) {
|
||||
for (uint8_t i = 0; i < count; i++) {
|
||||
Field field = fields[i];
|
||||
if (field.name == name) {
|
||||
return field;
|
||||
}
|
||||
}
|
||||
return Field();
|
||||
}
|
||||
|
||||
String getFieldValue(String name, FieldList fields, uint8_t count) {
|
||||
Field field = getField(name, fields, count);
|
||||
if (field.getValue) {
|
||||
return field.getValue();
|
||||
}
|
||||
return String();
|
||||
}
|
||||
|
||||
CRGB parseColor(String value) {
|
||||
uint8_t ri = value.indexOf(",");
|
||||
uint8_t gi = value.indexOf(",", ri + 1);
|
||||
|
||||
String rs = value.substring(0, ri);
|
||||
String gs = value.substring(ri + 1, gi);
|
||||
String bs = value.substring(gi + 1);
|
||||
|
||||
uint8_t r = rs.toInt();
|
||||
uint8_t g = gs.toInt();
|
||||
uint8_t b = bs.toInt();
|
||||
|
||||
return CRGB(r, g, b);
|
||||
}
|
||||
|
||||
void writeFieldsToEEPROM(FieldList fields, uint8_t count) {
|
||||
uint8_t index = 0;
|
||||
|
||||
EEPROM.write(index, 0);
|
||||
|
||||
for (uint8_t i = 0; i < count; i++) {
|
||||
Field field = fields[i];
|
||||
if (!field.getValue && !field.setValue)
|
||||
continue;
|
||||
|
||||
String value = field.getValue();
|
||||
|
||||
if (field.type == ColorFieldType) {
|
||||
CRGB color = parseColor(value);
|
||||
EEPROM.write(index++, color.r);
|
||||
EEPROM.write(index++, color.g);
|
||||
EEPROM.write(index++, color.b);
|
||||
} else {
|
||||
byte v = value.toInt();
|
||||
EEPROM.write(index++, v);
|
||||
}
|
||||
}
|
||||
|
||||
EEPROM.commit();
|
||||
}
|
||||
|
||||
String setFieldValue(String name, String value, FieldList fields, uint8_t count) {
|
||||
String result;
|
||||
|
||||
Field field = getField(name, fields, count);
|
||||
if (field.setValue) {
|
||||
if (field.type == ColorFieldType) {
|
||||
String r = webServer.arg("r");
|
||||
String g = webServer.arg("g");
|
||||
String b = webServer.arg("b");
|
||||
String combinedValue = r + "," + g + "," + b;
|
||||
result = field.setValue(combinedValue);
|
||||
} else {
|
||||
result = field.setValue(value);
|
||||
}
|
||||
}
|
||||
|
||||
writeFieldsToEEPROM(fields, count);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void loadFieldsFromEEPROM(FieldList fields, uint8_t count) {
|
||||
uint8_t byteCount = 1;
|
||||
|
||||
for (uint8_t i = 0; i < count; i++) {
|
||||
Field field = fields[i];
|
||||
if (!field.setValue)
|
||||
continue;
|
||||
|
||||
if (field.type == ColorFieldType) {
|
||||
byteCount += 3;
|
||||
} else {
|
||||
byteCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!EEPROM.begin(count)) {
|
||||
Serial.println("Failed to initialize EEPROM!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (EEPROM.read(0) == 255) {
|
||||
Serial.println("First run, or EEPROM erased, skipping settings load!");
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t index = 0;
|
||||
|
||||
for (uint8_t i = 0; i < count; i++) {
|
||||
Field field = fields[i];
|
||||
if (!field.setValue)
|
||||
continue;
|
||||
|
||||
if (field.type == ColorFieldType) {
|
||||
String r = String(EEPROM.read(index++));
|
||||
String g = String(EEPROM.read(index++));
|
||||
String b = String(EEPROM.read(index++));
|
||||
field.setValue(r + "," + g + "," + b);
|
||||
} else {
|
||||
byte v = EEPROM.read(index++);
|
||||
field.setValue(String(v));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String getFieldsJson(FieldList fields, uint8_t count) {
|
||||
String json = "[";
|
||||
|
||||
for (uint8_t i = 0; i < count; i++) {
|
||||
Field field = fields[i];
|
||||
|
||||
json += "{\"name\":\"" + field.name + "\",\"label\":\"" + field.label + "\",\"type\":\"" + field.type + "\"";
|
||||
|
||||
if (field.getValue) {
|
||||
if (field.type == ColorFieldType || field.type == "String") {
|
||||
json += ",\"value\":\"" + field.getValue() + "\"";
|
||||
}
|
||||
else {
|
||||
json += ",\"value\":" + field.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
if (field.type == NumberFieldType) {
|
||||
json += ",\"min\":" + String(field.min);
|
||||
json += ",\"max\":" + String(field.max);
|
||||
}
|
||||
|
||||
if (field.getOptions) {
|
||||
json += ",\"options\":[";
|
||||
json += field.getOptions();
|
||||
json += "]";
|
||||
}
|
||||
|
||||
json += "}";
|
||||
|
||||
if (i < count - 1)
|
||||
json += ",";
|
||||
}
|
||||
|
||||
json += "]";
|
||||
|
||||
return json;
|
||||
}
|
||||
272
src/fields.h
Normal file
272
src/fields.h
Normal file
@ -0,0 +1,272 @@
|
||||
/*
|
||||
ESP32 FastLED WebServer: https://github.com/jasoncoon/esp32-fastled-webserver
|
||||
Copyright (C) 2017 Jason Coon
|
||||
|
||||
Built upon the amazing FastLED work of Daniel Garcia and Mark Kriegsman:
|
||||
https://github.com/FastLED/FastLED
|
||||
|
||||
ESP32 support provided by the hard work of Sam Guyer:
|
||||
https://github.com/samguyer/FastLED
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
String getPower() {
|
||||
return String(power);
|
||||
}
|
||||
|
||||
String setPower(String value) {
|
||||
power = value.toInt();
|
||||
power = power == 0 ? 0 : 1;
|
||||
return String(power);
|
||||
}
|
||||
|
||||
String getBrightness() {
|
||||
return String(brightness);
|
||||
}
|
||||
|
||||
String setBrightness(String value) {
|
||||
brightness = value.toInt();
|
||||
FastLED.setBrightness(brightness);
|
||||
return String(brightness);
|
||||
}
|
||||
|
||||
String getPattern() {
|
||||
return String(currentPatternIndex);
|
||||
}
|
||||
|
||||
void setPattern(uint8_t value)
|
||||
{
|
||||
if (value >= patternCount)
|
||||
value = patternCount - 1;
|
||||
|
||||
currentPatternIndex = value;
|
||||
}
|
||||
|
||||
String setPattern(String value) {
|
||||
setPattern(value.toInt());
|
||||
return String(currentPatternIndex);
|
||||
}
|
||||
|
||||
String getPatterns() {
|
||||
String json = "";
|
||||
|
||||
for (uint8_t i = 0; i < patternCount; i++) {
|
||||
json += "\"" + patterns[i].name + "\"";
|
||||
if (i < patternCount - 1)
|
||||
json += ",";
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
String getPalette() {
|
||||
return String(currentPaletteIndex);
|
||||
}
|
||||
|
||||
String setPalette(String value) {
|
||||
// value.toInt() returns long, while currentPaletteIndex is declared as uint8_t
|
||||
long tmp = value.toInt();
|
||||
// clamp to [0.. paletteCount-1]
|
||||
if (tmp < 1) {
|
||||
tmp = 1;
|
||||
} else if (tmp > (paletteCount-1)) {
|
||||
tmp = paletteCount-1;
|
||||
}
|
||||
currentPaletteIndex = tmp;
|
||||
targetPalette = palettes[currentPaletteIndex];
|
||||
return String(currentPaletteIndex);
|
||||
}
|
||||
|
||||
String getPalettes() {
|
||||
String json = "";
|
||||
|
||||
for (uint8_t i = 0; i < paletteCount; i++) {
|
||||
json += "\"" + paletteNames[i] + "\"";
|
||||
if (i < paletteCount - 1)
|
||||
json += ",";
|
||||
}
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
String getSpeed() {
|
||||
return String(speed);
|
||||
}
|
||||
|
||||
String setSpeed(String value) {
|
||||
speed = value.toInt();
|
||||
return String(speed);
|
||||
}
|
||||
|
||||
String getAutoplay() {
|
||||
return String(autoplay);
|
||||
}
|
||||
|
||||
String setAutoplay(String value) {
|
||||
autoplay = value.toInt();
|
||||
autoplay = autoplay == 0 ? 0 : 1;
|
||||
autoPlayTimeout = millis() + (autoplayDuration * 1000);
|
||||
return String(autoplay);
|
||||
}
|
||||
|
||||
String getAutoplayDuration() {
|
||||
return String(autoplayDuration);
|
||||
}
|
||||
|
||||
String setAutoplayDuration(String value) {
|
||||
// value.toInt() returns long, while autoplayDuration is declared as uint8_t
|
||||
long tmp = value.toInt();
|
||||
// clamp to [1..255]
|
||||
if (tmp < 1) {
|
||||
tmp = 1;
|
||||
} else if (tmp > 255) {
|
||||
tmp = 255;
|
||||
}
|
||||
autoplayDuration = tmp;
|
||||
autoPlayTimeout = millis() + (tmp * 1000);
|
||||
return String(autoplayDuration);
|
||||
}
|
||||
|
||||
String getCyclePalettes() {
|
||||
return String(cyclePalettes);
|
||||
}
|
||||
|
||||
String setCyclePalettes(String value) {
|
||||
cyclePalettes = value.toInt();
|
||||
cyclePalettes = cyclePalettes == 0 ? 0 : 1;
|
||||
paletteTimeout = millis() + (paletteDuration * 1000);
|
||||
return String(cyclePalettes);
|
||||
}
|
||||
|
||||
String getPaletteDuration() {
|
||||
return String(paletteDuration);
|
||||
}
|
||||
|
||||
String setPaletteDuration(String value) {
|
||||
// value.toInt() returns long, while paletteDuration is declared as uint8_t
|
||||
long tmp = value.toInt();
|
||||
// clamp to [1..255]
|
||||
if (tmp < 1) {
|
||||
tmp = 1;
|
||||
} else if (tmp > 255) {
|
||||
tmp = 255;
|
||||
}
|
||||
paletteDuration = tmp;
|
||||
paletteTimeout = millis() + (tmp * 1000);
|
||||
return String(paletteDuration);
|
||||
}
|
||||
|
||||
String getSolidColor() {
|
||||
return String(solidColor.r) + "," + String(solidColor.g) + "," + String(solidColor.b);
|
||||
}
|
||||
|
||||
String setSolidColor(uint8_t r, uint8_t g, uint8_t b)
|
||||
{
|
||||
solidColor = CRGB(r, g, b);
|
||||
|
||||
return "\"" + String(solidColor.r) + "," + String(solidColor.g) + "," + String(solidColor.b) + "\"";
|
||||
}
|
||||
|
||||
String setSolidColor(CRGB color) {
|
||||
return setSolidColor(color.r, color.g, color.b);
|
||||
}
|
||||
|
||||
String setSolidColor(String value) {
|
||||
CRGB color = parseColor(value);
|
||||
|
||||
return setSolidColor(color);
|
||||
}
|
||||
|
||||
String getCooling() {
|
||||
return String(cooling);
|
||||
}
|
||||
|
||||
String setCooling(String value) {
|
||||
cooling = value.toInt();
|
||||
return String(cooling);
|
||||
}
|
||||
|
||||
String getSparking() {
|
||||
return String(sparking);
|
||||
}
|
||||
|
||||
String setSparking(String value) {
|
||||
sparking = value.toInt();
|
||||
return String(sparking);
|
||||
}
|
||||
|
||||
String getTwinkleSpeed() {
|
||||
return String(twinkleSpeed);
|
||||
}
|
||||
|
||||
String setTwinkleSpeed(String value) {
|
||||
// value.toInt() returns long, while twinkleSpeed is declared as uint8_t
|
||||
long tmp = value.toInt();
|
||||
// clamp to [0..8]
|
||||
if (tmp < 0) {
|
||||
tmp = 0;
|
||||
} else if (tmp > 8) {
|
||||
tmp = 8;
|
||||
}
|
||||
twinkleSpeed = tmp;
|
||||
return String(twinkleSpeed);
|
||||
}
|
||||
|
||||
String getTwinkleDensity() {
|
||||
return String(twinkleDensity);
|
||||
}
|
||||
|
||||
String setTwinkleDensity(String value) {
|
||||
// value.toInt() returns long, while twinkleDensity is declared as uint8_t
|
||||
long tmp = value.toInt();
|
||||
// clamp to [0..8]
|
||||
if (tmp < 0) {
|
||||
tmp = 0;
|
||||
} else if (tmp > 8) {
|
||||
tmp = 8;
|
||||
}
|
||||
twinkleDensity = tmp;
|
||||
return String(twinkleDensity);
|
||||
}
|
||||
|
||||
FieldList fields = {
|
||||
// name label type min, max, getValue, getOptions, setValue
|
||||
{ "power", "Power", BooleanFieldType, 0, 1, getPower, NULL, setPower },
|
||||
{ "brightness", "Brightness", NumberFieldType, 1, 255, getBrightness, NULL, setBrightness },
|
||||
{ "speed", "Speed", NumberFieldType, 1, 255, getSpeed, NULL, setSpeed },
|
||||
|
||||
{ "patternSection", "Pattern", SectionFieldType, 0, 0, NULL, NULL, NULL },
|
||||
{ "pattern", "Pattern", SelectFieldType, 0, patternCount, getPattern, getPatterns, setPattern },
|
||||
{ "autoplay", "Cycle Patterns", BooleanFieldType, 0, 1, getAutoplay, NULL, setAutoplay },
|
||||
{ "autoplayDuration", "Pattern Duration", NumberFieldType, 1, 255, getAutoplayDuration, NULL, setAutoplayDuration },
|
||||
|
||||
{ "paletteSection", "Palette", SectionFieldType, 0, 0, NULL, NULL, NULL },
|
||||
{ "palette", "Palette", SelectFieldType, 0, paletteCount, getPalette, getPalettes, setPalette },
|
||||
{ "cyclePalettes", "Cycle Palettes", BooleanFieldType, 0, 1, getCyclePalettes, NULL, setCyclePalettes },
|
||||
{ "paletteDuration", "Palette Duration", NumberFieldType, 1, 255, getPaletteDuration, NULL, setPaletteDuration },
|
||||
|
||||
{ "solidColorSection", "Solid Color", SectionFieldType, 0, 0, NULL, NULL, NULL },
|
||||
{ "solidColor", "Color", ColorFieldType, 0, 255, getSolidColor, NULL, setSolidColor },
|
||||
|
||||
{ "fire", "Fire & Water", SectionFieldType, 0, 0, NULL, NULL, NULL },
|
||||
{ "cooling", "Cooling", NumberFieldType, 0, 255, getCooling, NULL, setCooling },
|
||||
{ "sparking", "Sparking", NumberFieldType, 0, 255, getSparking, NULL, setSparking },
|
||||
|
||||
{ "twinklesSection", "Twinkles", SectionFieldType, 0, 0, NULL, NULL, NULL },
|
||||
{ "twinkleSpeed", "Twinkle Speed", NumberFieldType, 0, 8, getTwinkleSpeed, NULL, setTwinkleSpeed },
|
||||
{ "twinkleDensity", "Twinkle Density", NumberFieldType, 0, 8, getTwinkleDensity, NULL, setTwinkleDensity },
|
||||
};
|
||||
|
||||
uint8_t fieldCount = ARRAY_SIZE(fields);
|
||||
467
src/gradientPalettes.h
Normal file
467
src/gradientPalettes.h
Normal file
@ -0,0 +1,467 @@
|
||||
// From ColorWavesWithPalettes by Mark Kriegsman: https://gist.github.com/kriegsman/8281905786e8b2632aeb
|
||||
|
||||
// Gradient Color Palette definitions for 33 different cpt-city color palettes.
|
||||
// 956 bytes of PROGMEM for all of the palettes together,
|
||||
// +618 bytes of PROGMEM for gradient palette code (AVR).
|
||||
// 1,494 bytes total for all 34 color palettes and associated code.
|
||||
|
||||
// Gradient palette "ib_jul01_gp", originally from
|
||||
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/ing/xmas/tn/ib_jul01.png.index.html
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 16 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( ib_jul01_gp ) {
|
||||
0, 194, 1, 1,
|
||||
94, 1, 29, 18,
|
||||
132, 57,131, 28,
|
||||
255, 113, 1, 1};
|
||||
|
||||
// Gradient palette "es_vintage_57_gp", originally from
|
||||
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/es/vintage/tn/es_vintage_57.png.index.html
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 20 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( es_vintage_57_gp ) {
|
||||
0, 2, 1, 1,
|
||||
53, 18, 1, 0,
|
||||
104, 69, 29, 1,
|
||||
153, 167,135, 10,
|
||||
255, 46, 56, 4};
|
||||
|
||||
// Gradient palette "es_vintage_01_gp", originally from
|
||||
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/es/vintage/tn/es_vintage_01.png.index.html
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 32 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( es_vintage_01_gp ) {
|
||||
0, 4, 1, 1,
|
||||
51, 16, 0, 1,
|
||||
76, 97,104, 3,
|
||||
101, 255,131, 19,
|
||||
127, 67, 9, 4,
|
||||
153, 16, 0, 1,
|
||||
229, 4, 1, 1,
|
||||
255, 4, 1, 1};
|
||||
|
||||
// Gradient palette "es_rivendell_15_gp", originally from
|
||||
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/es/rivendell/tn/es_rivendell_15.png.index.html
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 20 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( es_rivendell_15_gp ) {
|
||||
0, 1, 14, 5,
|
||||
101, 16, 36, 14,
|
||||
165, 56, 68, 30,
|
||||
242, 150,156, 99,
|
||||
255, 150,156, 99};
|
||||
|
||||
// Gradient palette "rgi_15_gp", originally from
|
||||
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/ds/rgi/tn/rgi_15.png.index.html
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 36 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( rgi_15_gp ) {
|
||||
0, 4, 1, 31,
|
||||
31, 55, 1, 16,
|
||||
63, 197, 3, 7,
|
||||
95, 59, 2, 17,
|
||||
127, 6, 2, 34,
|
||||
159, 39, 6, 33,
|
||||
191, 112, 13, 32,
|
||||
223, 56, 9, 35,
|
||||
255, 22, 6, 38};
|
||||
|
||||
// Gradient palette "retro2_16_gp", originally from
|
||||
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/ma/retro2/tn/retro2_16.png.index.html
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 8 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( retro2_16_gp ) {
|
||||
0, 188,135, 1,
|
||||
255, 46, 7, 1};
|
||||
|
||||
// Gradient palette "Analogous_1_gp", originally from
|
||||
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/red/tn/Analogous_1.png.index.html
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 20 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( Analogous_1_gp ) {
|
||||
0, 3, 0,255,
|
||||
63, 23, 0,255,
|
||||
127, 67, 0,255,
|
||||
191, 142, 0, 45,
|
||||
255, 255, 0, 0};
|
||||
|
||||
// Gradient palette "es_pinksplash_08_gp", originally from
|
||||
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/es/pink_splash/tn/es_pinksplash_08.png.index.html
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 20 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( es_pinksplash_08_gp ) {
|
||||
0, 126, 11,255,
|
||||
127, 197, 1, 22,
|
||||
175, 210,157,172,
|
||||
221, 157, 3,112,
|
||||
255, 157, 3,112};
|
||||
|
||||
// Gradient palette "es_pinksplash_07_gp", originally from
|
||||
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/es/pink_splash/tn/es_pinksplash_07.png.index.html
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 28 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( es_pinksplash_07_gp ) {
|
||||
0, 229, 1, 1,
|
||||
61, 242, 4, 63,
|
||||
101, 255, 12,255,
|
||||
127, 249, 81,252,
|
||||
153, 255, 11,235,
|
||||
193, 244, 5, 68,
|
||||
255, 232, 1, 5};
|
||||
|
||||
// Gradient palette "Coral_reef_gp", originally from
|
||||
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/other/tn/Coral_reef.png.index.html
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 24 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( Coral_reef_gp ) {
|
||||
0, 40,199,197,
|
||||
50, 10,152,155,
|
||||
96, 1,111,120,
|
||||
96, 43,127,162,
|
||||
139, 10, 73,111,
|
||||
255, 1, 34, 71};
|
||||
|
||||
// Gradient palette "es_ocean_breeze_068_gp", originally from
|
||||
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/es/ocean_breeze/tn/es_ocean_breeze_068.png.index.html
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 24 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( es_ocean_breeze_068_gp ) {
|
||||
0, 100,156,153,
|
||||
51, 1, 99,137,
|
||||
101, 1, 68, 84,
|
||||
104, 35,142,168,
|
||||
178, 0, 63,117,
|
||||
255, 1, 10, 10};
|
||||
|
||||
// Gradient palette "es_ocean_breeze_036_gp", originally from
|
||||
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/es/ocean_breeze/tn/es_ocean_breeze_036.png.index.html
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 16 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( es_ocean_breeze_036_gp ) {
|
||||
0, 1, 6, 7,
|
||||
89, 1, 99,111,
|
||||
153, 144,209,255,
|
||||
255, 0, 73, 82};
|
||||
|
||||
// Gradient palette "departure_gp", originally from
|
||||
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/mjf/tn/departure.png.index.html
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 88 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( departure_gp ) {
|
||||
0, 8, 3, 0,
|
||||
42, 23, 7, 0,
|
||||
63, 75, 38, 6,
|
||||
84, 169, 99, 38,
|
||||
106, 213,169,119,
|
||||
116, 255,255,255,
|
||||
138, 135,255,138,
|
||||
148, 22,255, 24,
|
||||
170, 0,255, 0,
|
||||
191, 0,136, 0,
|
||||
212, 0, 55, 0,
|
||||
255, 0, 55, 0};
|
||||
|
||||
// Gradient palette "es_landscape_64_gp", originally from
|
||||
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/es/landscape/tn/es_landscape_64.png.index.html
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 36 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( es_landscape_64_gp ) {
|
||||
0, 0, 0, 0,
|
||||
37, 2, 25, 1,
|
||||
76, 15,115, 5,
|
||||
127, 79,213, 1,
|
||||
128, 126,211, 47,
|
||||
130, 188,209,247,
|
||||
153, 144,182,205,
|
||||
204, 59,117,250,
|
||||
255, 1, 37,192};
|
||||
|
||||
// Gradient palette "es_landscape_33_gp", originally from
|
||||
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/es/landscape/tn/es_landscape_33.png.index.html
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 24 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( es_landscape_33_gp ) {
|
||||
0, 1, 5, 0,
|
||||
19, 32, 23, 1,
|
||||
38, 161, 55, 1,
|
||||
63, 229,144, 1,
|
||||
66, 39,142, 74,
|
||||
255, 1, 4, 1};
|
||||
|
||||
// Gradient palette "rainbowsherbet_gp", originally from
|
||||
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/ma/icecream/tn/rainbowsherbet.png.index.html
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 28 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( rainbowsherbet_gp ) {
|
||||
0, 255, 33, 4,
|
||||
43, 255, 68, 25,
|
||||
86, 255, 7, 25,
|
||||
127, 255, 82,103,
|
||||
170, 255,255,242,
|
||||
209, 42,255, 22,
|
||||
255, 87,255, 65};
|
||||
|
||||
// Gradient palette "gr65_hult_gp", originally from
|
||||
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/hult/tn/gr65_hult.png.index.html
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 24 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( gr65_hult_gp ) {
|
||||
0, 247,176,247,
|
||||
48, 255,136,255,
|
||||
89, 220, 29,226,
|
||||
160, 7, 82,178,
|
||||
216, 1,124,109,
|
||||
255, 1,124,109};
|
||||
|
||||
// Gradient palette "gr64_hult_gp", originally from
|
||||
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/hult/tn/gr64_hult.png.index.html
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 32 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( gr64_hult_gp ) {
|
||||
0, 1,124,109,
|
||||
66, 1, 93, 79,
|
||||
104, 52, 65, 1,
|
||||
130, 115,127, 1,
|
||||
150, 52, 65, 1,
|
||||
201, 1, 86, 72,
|
||||
239, 0, 55, 45,
|
||||
255, 0, 55, 45};
|
||||
|
||||
// Gradient palette "GMT_drywet_gp", originally from
|
||||
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/gmt/tn/GMT_drywet.png.index.html
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 28 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( GMT_drywet_gp ) {
|
||||
0, 47, 30, 2,
|
||||
42, 213,147, 24,
|
||||
84, 103,219, 52,
|
||||
127, 3,219,207,
|
||||
170, 1, 48,214,
|
||||
212, 1, 1,111,
|
||||
255, 1, 7, 33};
|
||||
|
||||
// Gradient palette "ib15_gp", originally from
|
||||
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/ing/general/tn/ib15.png.index.html
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 24 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( ib15_gp ) {
|
||||
0, 113, 91,147,
|
||||
72, 157, 88, 78,
|
||||
89, 208, 85, 33,
|
||||
107, 255, 29, 11,
|
||||
141, 137, 31, 39,
|
||||
255, 59, 33, 89};
|
||||
|
||||
// Gradient palette "Fuschia_7_gp", originally from
|
||||
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/ds/fuschia/tn/Fuschia-7.png.index.html
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 20 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( Fuschia_7_gp ) {
|
||||
0, 43, 3,153,
|
||||
63, 100, 4,103,
|
||||
127, 188, 5, 66,
|
||||
191, 161, 11,115,
|
||||
255, 135, 20,182};
|
||||
|
||||
// Gradient palette "es_emerald_dragon_08_gp", originally from
|
||||
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/es/emerald_dragon/tn/es_emerald_dragon_08.png.index.html
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 16 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( es_emerald_dragon_08_gp ) {
|
||||
0, 97,255, 1,
|
||||
101, 47,133, 1,
|
||||
178, 13, 43, 1,
|
||||
255, 2, 10, 1};
|
||||
|
||||
// Gradient palette "lava_gp", originally from
|
||||
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/neota/elem/tn/lava.png.index.html
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 52 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( lava_gp ) {
|
||||
0, 0, 0, 0,
|
||||
46, 18, 0, 0,
|
||||
96, 113, 0, 0,
|
||||
108, 142, 3, 1,
|
||||
119, 175, 17, 1,
|
||||
146, 213, 44, 2,
|
||||
174, 255, 82, 4,
|
||||
188, 255,115, 4,
|
||||
202, 255,156, 4,
|
||||
218, 255,203, 4,
|
||||
234, 255,255, 4,
|
||||
244, 255,255, 71,
|
||||
255, 255,255,255};
|
||||
|
||||
// Gradient palette "fire_gp", originally from
|
||||
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/neota/elem/tn/fire.png.index.html
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 28 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( fire_gp ) {
|
||||
0, 1, 1, 0,
|
||||
76, 32, 5, 0,
|
||||
146, 192, 24, 0,
|
||||
197, 220,105, 5,
|
||||
240, 252,255, 31,
|
||||
250, 252,255,111,
|
||||
255, 255,255,255};
|
||||
|
||||
// Gradient palette "Colorfull_gp", originally from
|
||||
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/atmospheric/tn/Colorfull.png.index.html
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 44 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( Colorfull_gp ) {
|
||||
0, 10, 85, 5,
|
||||
25, 29,109, 18,
|
||||
60, 59,138, 42,
|
||||
93, 83, 99, 52,
|
||||
106, 110, 66, 64,
|
||||
109, 123, 49, 65,
|
||||
113, 139, 35, 66,
|
||||
116, 192,117, 98,
|
||||
124, 255,255,137,
|
||||
168, 100,180,155,
|
||||
255, 22,121,174};
|
||||
|
||||
// Gradient palette "Magenta_Evening_gp", originally from
|
||||
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/atmospheric/tn/Magenta_Evening.png.index.html
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 28 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( Magenta_Evening_gp ) {
|
||||
0, 71, 27, 39,
|
||||
31, 130, 11, 51,
|
||||
63, 213, 2, 64,
|
||||
70, 232, 1, 66,
|
||||
76, 252, 1, 69,
|
||||
108, 123, 2, 51,
|
||||
255, 46, 9, 35};
|
||||
|
||||
// Gradient palette "Pink_Purple_gp", originally from
|
||||
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/atmospheric/tn/Pink_Purple.png.index.html
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 44 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( Pink_Purple_gp ) {
|
||||
0, 19, 2, 39,
|
||||
25, 26, 4, 45,
|
||||
51, 33, 6, 52,
|
||||
76, 68, 62,125,
|
||||
102, 118,187,240,
|
||||
109, 163,215,247,
|
||||
114, 217,244,255,
|
||||
122, 159,149,221,
|
||||
149, 113, 78,188,
|
||||
183, 128, 57,155,
|
||||
255, 146, 40,123};
|
||||
|
||||
// Gradient palette "Sunset_Real_gp", originally from
|
||||
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/atmospheric/tn/Sunset_Real.png.index.html
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 28 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( Sunset_Real_gp ) {
|
||||
0, 120, 0, 0,
|
||||
22, 179, 22, 0,
|
||||
51, 255,104, 0,
|
||||
85, 167, 22, 18,
|
||||
135, 100, 0,103,
|
||||
198, 16, 0,130,
|
||||
255, 0, 0,160};
|
||||
|
||||
// Gradient palette "es_autumn_19_gp", originally from
|
||||
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/es/autumn/tn/es_autumn_19.png.index.html
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 52 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( es_autumn_19_gp ) {
|
||||
0, 26, 1, 1,
|
||||
51, 67, 4, 1,
|
||||
84, 118, 14, 1,
|
||||
104, 137,152, 52,
|
||||
112, 113, 65, 1,
|
||||
122, 133,149, 59,
|
||||
124, 137,152, 52,
|
||||
135, 113, 65, 1,
|
||||
142, 139,154, 46,
|
||||
163, 113, 13, 1,
|
||||
204, 55, 3, 1,
|
||||
249, 17, 1, 1,
|
||||
255, 17, 1, 1};
|
||||
|
||||
// Gradient palette "BlacK_Blue_Magenta_White_gp", originally from
|
||||
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/basic/tn/BlacK_Blue_Magenta_White.png.index.html
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 28 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( BlacK_Blue_Magenta_White_gp ) {
|
||||
0, 0, 0, 0,
|
||||
42, 0, 0, 45,
|
||||
84, 0, 0,255,
|
||||
127, 42, 0,255,
|
||||
170, 255, 0,255,
|
||||
212, 255, 55,255,
|
||||
255, 255,255,255};
|
||||
|
||||
// Gradient palette "BlacK_Magenta_Red_gp", originally from
|
||||
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/basic/tn/BlacK_Magenta_Red.png.index.html
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 20 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( BlacK_Magenta_Red_gp ) {
|
||||
0, 0, 0, 0,
|
||||
63, 42, 0, 45,
|
||||
127, 255, 0,255,
|
||||
191, 255, 0, 45,
|
||||
255, 255, 0, 0};
|
||||
|
||||
// Gradient palette "BlacK_Red_Magenta_Yellow_gp", originally from
|
||||
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/basic/tn/BlacK_Red_Magenta_Yellow.png.index.html
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 28 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( BlacK_Red_Magenta_Yellow_gp ) {
|
||||
0, 0, 0, 0,
|
||||
42, 42, 0, 0,
|
||||
84, 255, 0, 0,
|
||||
127, 255, 0, 45,
|
||||
170, 255, 0,255,
|
||||
212, 255, 55, 45,
|
||||
255, 255,255, 0};
|
||||
|
||||
// Gradient palette "Blue_Cyan_Yellow_gp", originally from
|
||||
// http://soliton.vm.bytemark.co.uk/pub/cpt-city/nd/basic/tn/Blue_Cyan_Yellow.png.index.html
|
||||
// converted for FastLED with gammas (2.6, 2.2, 2.5)
|
||||
// Size: 20 bytes of program space.
|
||||
|
||||
DEFINE_GRADIENT_PALETTE( Blue_Cyan_Yellow_gp ) {
|
||||
0, 0, 0,255,
|
||||
63, 0, 55,255,
|
||||
127, 0,255,255,
|
||||
191, 42,255, 45,
|
||||
255, 255,255, 0};
|
||||
|
||||
224
src/palettes.h
Normal file
224
src/palettes.h
Normal file
@ -0,0 +1,224 @@
|
||||
/*
|
||||
ESP32 FastLED WebServer: https://github.com/jasoncoon/esp32-fastled-webserver
|
||||
Copyright (C) 2017 Jason Coon
|
||||
|
||||
Built upon the amazing FastLED work of Daniel Garcia and Mark Kriegsman:
|
||||
https://github.com/FastLED/FastLED
|
||||
|
||||
ESP32 support provided by the hard work of Sam Guyer:
|
||||
https://github.com/samguyer/FastLED
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// A mostly red palette with green accents and white trim.
|
||||
// "CRGB::Gray" is used as white to keep the brightness more uniform.
|
||||
const TProgmemRGBPalette16 RedGreenWhite_p FL_PROGMEM =
|
||||
{ CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red,
|
||||
CRGB::Red, CRGB::Red, CRGB::Red, CRGB::Red,
|
||||
CRGB::Red, CRGB::Red, CRGB::Gray, CRGB::Gray,
|
||||
CRGB::Green, CRGB::Green, CRGB::Green, CRGB::Green
|
||||
};
|
||||
|
||||
// A mostly (dark) green palette with red berries.
|
||||
#define Holly_Green 0x00580c
|
||||
#define Holly_Red 0xB00402
|
||||
const TProgmemRGBPalette16 Holly_p FL_PROGMEM =
|
||||
{ Holly_Green, Holly_Green, Holly_Green, Holly_Green,
|
||||
Holly_Green, Holly_Green, Holly_Green, Holly_Green,
|
||||
Holly_Green, Holly_Green, Holly_Green, Holly_Green,
|
||||
Holly_Green, Holly_Green, Holly_Green, Holly_Red
|
||||
};
|
||||
|
||||
// A red and white striped palette
|
||||
// "CRGB::Gray" is used as white to keep the brightness more uniform.
|
||||
const TProgmemRGBPalette16 RedWhite_p FL_PROGMEM =
|
||||
{ CRGB::Red, CRGB::Red, CRGB::Gray, CRGB::Gray,
|
||||
CRGB::Red, CRGB::Red, CRGB::Gray, CRGB::Gray,
|
||||
CRGB::Red, CRGB::Red, CRGB::Gray, CRGB::Gray,
|
||||
CRGB::Red, CRGB::Red, CRGB::Gray, CRGB::Gray
|
||||
};
|
||||
|
||||
// A mostly blue palette with white accents.
|
||||
// "CRGB::Gray" is used as white to keep the brightness more uniform.
|
||||
const TProgmemRGBPalette16 BlueWhite_p FL_PROGMEM =
|
||||
{ CRGB::Blue, CRGB::Blue, CRGB::Blue, CRGB::Blue,
|
||||
CRGB::Blue, CRGB::Blue, CRGB::Blue, CRGB::Blue,
|
||||
CRGB::Blue, CRGB::Blue, CRGB::Blue, CRGB::Blue,
|
||||
CRGB::Blue, CRGB::Gray, CRGB::Gray, CRGB::Gray
|
||||
};
|
||||
|
||||
// A pure "fairy light" palette with some brightness variations
|
||||
#define HALFFAIRY ((CRGB::FairyLight & 0xFEFEFE) / 2)
|
||||
#define QUARTERFAIRY ((CRGB::FairyLight & 0xFCFCFC) / 4)
|
||||
const TProgmemRGBPalette16 FairyLight_p FL_PROGMEM =
|
||||
{ CRGB::FairyLight, CRGB::FairyLight, CRGB::FairyLight, CRGB::FairyLight,
|
||||
HALFFAIRY, HALFFAIRY, CRGB::FairyLight, CRGB::FairyLight,
|
||||
QUARTERFAIRY, QUARTERFAIRY, CRGB::FairyLight, CRGB::FairyLight,
|
||||
CRGB::FairyLight, CRGB::FairyLight, CRGB::FairyLight, CRGB::FairyLight
|
||||
};
|
||||
|
||||
// A palette of soft snowflakes with the occasional bright one
|
||||
const TProgmemRGBPalette16 Snow_p FL_PROGMEM =
|
||||
{ 0x304048, 0x304048, 0x304048, 0x304048,
|
||||
0x304048, 0x304048, 0x304048, 0x304048,
|
||||
0x304048, 0x304048, 0x304048, 0x304048,
|
||||
0x304048, 0x304048, 0x304048, 0xE0F0FF
|
||||
};
|
||||
|
||||
// A palette reminiscent of large 'old-school' C9-size tree lights
|
||||
// in the five classic colors: red, orange, green, blue, and white.
|
||||
#define C9_Red 0xB80400
|
||||
#define C9_Orange 0x902C02
|
||||
#define C9_Green 0x046002
|
||||
#define C9_Blue 0x070758
|
||||
#define C9_White 0x606820
|
||||
const TProgmemRGBPalette16 RetroC9_p FL_PROGMEM =
|
||||
{ C9_Red, C9_Orange, C9_Red, C9_Orange,
|
||||
C9_Orange, C9_Red, C9_Orange, C9_Red,
|
||||
C9_Green, C9_Green, C9_Green, C9_Green,
|
||||
C9_Blue, C9_Blue, C9_Blue,
|
||||
C9_White
|
||||
};
|
||||
|
||||
// A cold, icy pale blue palette
|
||||
#define Ice_Blue1 0x0C1040
|
||||
#define Ice_Blue2 0x182080
|
||||
#define Ice_Blue3 0x5080C0
|
||||
const TProgmemRGBPalette16 IcyBlue_p FL_PROGMEM =
|
||||
{
|
||||
Ice_Blue1, Ice_Blue1, Ice_Blue1, Ice_Blue1,
|
||||
Ice_Blue1, Ice_Blue1, Ice_Blue1, Ice_Blue1,
|
||||
Ice_Blue1, Ice_Blue1, Ice_Blue1, Ice_Blue1,
|
||||
Ice_Blue2, Ice_Blue2, Ice_Blue2, Ice_Blue3
|
||||
};
|
||||
|
||||
CRGBPalette16 IceColors_p = CRGBPalette16(CRGB::Black, CRGB::Blue, CRGB::Aqua, CRGB::White);
|
||||
|
||||
#include "gradientPalettes.h"
|
||||
|
||||
const CRGBPalette16 palettes[] = {
|
||||
RainbowColors_p,
|
||||
RainbowStripeColors_p,
|
||||
CloudColors_p,
|
||||
LavaColors_p,
|
||||
OceanColors_p,
|
||||
ForestColors_p,
|
||||
PartyColors_p,
|
||||
HeatColors_p,
|
||||
|
||||
IceColors_p,
|
||||
IcyBlue_p,
|
||||
Snow_p,
|
||||
RedWhite_p,
|
||||
BlueWhite_p,
|
||||
FairyLight_p,
|
||||
RetroC9_p,
|
||||
RedGreenWhite_p,
|
||||
Holly_p,
|
||||
|
||||
Sunset_Real_gp,
|
||||
es_rivendell_15_gp,
|
||||
es_ocean_breeze_036_gp,
|
||||
rgi_15_gp,
|
||||
retro2_16_gp,
|
||||
Analogous_1_gp,
|
||||
es_pinksplash_08_gp,
|
||||
Coral_reef_gp,
|
||||
es_ocean_breeze_068_gp,
|
||||
es_pinksplash_07_gp,
|
||||
es_vintage_01_gp,
|
||||
departure_gp,
|
||||
es_landscape_64_gp,
|
||||
es_landscape_33_gp,
|
||||
rainbowsherbet_gp,
|
||||
gr65_hult_gp,
|
||||
gr64_hult_gp,
|
||||
GMT_drywet_gp,
|
||||
ib_jul01_gp,
|
||||
es_vintage_57_gp,
|
||||
ib15_gp,
|
||||
Fuschia_7_gp,
|
||||
es_emerald_dragon_08_gp,
|
||||
lava_gp,
|
||||
fire_gp,
|
||||
Colorfull_gp,
|
||||
Magenta_Evening_gp,
|
||||
Pink_Purple_gp,
|
||||
es_autumn_19_gp,
|
||||
BlacK_Blue_Magenta_White_gp,
|
||||
BlacK_Magenta_Red_gp,
|
||||
BlacK_Red_Magenta_Yellow_gp,
|
||||
Blue_Cyan_Yellow_gp,
|
||||
};
|
||||
|
||||
const uint8_t paletteCount = ARRAY_SIZE(palettes);
|
||||
|
||||
const String paletteNames[paletteCount] = {
|
||||
"Rainbow",
|
||||
"Rainbow Stripe",
|
||||
"Cloud",
|
||||
"Lava",
|
||||
"Ocean",
|
||||
"Forest",
|
||||
"Party",
|
||||
"Heat",
|
||||
|
||||
"Ice",
|
||||
"Icy Blue",
|
||||
"Snow",
|
||||
"Red & White",
|
||||
"Blue & White",
|
||||
"Fairy",
|
||||
"Retro C9",
|
||||
"Red, Green & White",
|
||||
"Holly",
|
||||
|
||||
"Sunset_Real",
|
||||
"es_rivendell_15",
|
||||
"es_ocean_breeze_036",
|
||||
"rgi_15",
|
||||
"retro2_16",
|
||||
"Analogous_1",
|
||||
"es_pinksplash_08",
|
||||
"Coral_reef",
|
||||
"es_ocean_breeze_068",
|
||||
"es_pinksplash_07",
|
||||
"es_vintage_01",
|
||||
"departure",
|
||||
"es_landscape_64",
|
||||
"es_landscape_33",
|
||||
"rainbowsherbet",
|
||||
"gr65_hult",
|
||||
"gr64_hult",
|
||||
"GMT_drywet",
|
||||
"ib_jul01",
|
||||
"es_vintage_57",
|
||||
"ib15",
|
||||
"Fuschia_7",
|
||||
"es_emerald_dragon_08",
|
||||
"lava",
|
||||
"fire",
|
||||
"Colorfull",
|
||||
"Magenta_Evening",
|
||||
"Pink_Purple",
|
||||
"es_autumn_19",
|
||||
"BlacK_Blue_Magenta_White",
|
||||
"BlacK_Magenta_Red",
|
||||
"BlacK_Red_Magenta_Yellow",
|
||||
"Blue_Cyan_Yellow",
|
||||
};
|
||||
|
||||
CRGBPalette16 currentPalette( CRGB::Black);
|
||||
CRGBPalette16 targetPalette( palettes[0] );
|
||||
285
src/patterns.h
Normal file
285
src/patterns.h
Normal file
@ -0,0 +1,285 @@
|
||||
/*
|
||||
ESP32 FastLED WebServer: https://github.com/jasoncoon/esp32-fastled-webserver
|
||||
Copyright (C) 2017 Jason Coon
|
||||
|
||||
Built upon the amazing FastLED work of Daniel Garcia and Mark Kriegsman:
|
||||
https://github.com/FastLED/FastLED
|
||||
|
||||
ESP32 support provided by the hard work of Sam Guyer:
|
||||
https://github.com/samguyer/FastLED
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "palettes.h"
|
||||
#include "twinkleFox.h"
|
||||
|
||||
void rainbow()
|
||||
{
|
||||
// FastLED's built-in rainbow generator
|
||||
fill_rainbow( leds, NUM_LEDS, gHue, speed);
|
||||
}
|
||||
|
||||
void addGlitter( fract8 chanceOfGlitter)
|
||||
{
|
||||
if ( random8() < chanceOfGlitter) {
|
||||
leds[ random16(NUM_LEDS) ] += CRGB::White;
|
||||
}
|
||||
}
|
||||
|
||||
void rainbowWithGlitter()
|
||||
{
|
||||
// built-in FastLED rainbow, plus some random sparkly glitter
|
||||
rainbow();
|
||||
addGlitter(80);
|
||||
}
|
||||
|
||||
void confetti()
|
||||
{
|
||||
// random colored speckles that blink in and fade smoothly
|
||||
fadeToBlackBy( leds, NUM_LEDS, 10);
|
||||
int pos = random16(NUM_LEDS);
|
||||
leds[pos] += CHSV( gHue + random8(64), 200, 255);
|
||||
}
|
||||
|
||||
void sinelon()
|
||||
{
|
||||
// a colored dot sweeping back and forth, with fading trails
|
||||
fadeToBlackBy( leds, NUM_LEDS, 20);
|
||||
int pos = beatsin16(speed, 0, NUM_LEDS - 1);
|
||||
static int prevpos = 0;
|
||||
CRGB color = ColorFromPalette(palettes[currentPaletteIndex], gHue, 255);
|
||||
if ( pos < prevpos ) {
|
||||
fill_solid( leds + pos, (prevpos - pos) + 1, color);
|
||||
} else {
|
||||
fill_solid( leds + prevpos, (pos - prevpos) + 1, color);
|
||||
}
|
||||
prevpos = pos;
|
||||
}
|
||||
|
||||
void bpm()
|
||||
{
|
||||
// colored stripes pulsing at a defined Beats-Per-Minute (BPM)
|
||||
uint8_t beat = beatsin8( speed, 64, 255);
|
||||
CRGBPalette16 palette = palettes[currentPaletteIndex];
|
||||
for ( int i = 0; i < NUM_LEDS; i++) {
|
||||
leds[i] = ColorFromPalette(palette, gHue + (i * 2), beat - gHue + (i * 10));
|
||||
}
|
||||
}
|
||||
|
||||
void juggle() {
|
||||
// eight colored dots, weaving in and out of sync with each other
|
||||
fadeToBlackBy( leds, NUM_LEDS, 20);
|
||||
byte dothue = 0;
|
||||
for ( int i = 0; i < 8; i++) {
|
||||
leds[beatsin16( i + speed, 0, NUM_LEDS - 1 )] |= CHSV(dothue, 200, 255);
|
||||
dothue += 32;
|
||||
}
|
||||
}
|
||||
|
||||
void showSolidColor()
|
||||
{
|
||||
fill_solid(leds, NUM_LEDS, solidColor);
|
||||
}
|
||||
|
||||
// based on FastLED example Fire2012WithPalette: https://github.com/FastLED/FastLED/blob/master/examples/Fire2012WithPalette/Fire2012WithPalette.ino
|
||||
void heatMap(CRGBPalette16 palette, bool up)
|
||||
{
|
||||
fill_solid(leds, NUM_LEDS, CRGB::Black);
|
||||
|
||||
// Add entropy to random number generator; we use a lot of it.
|
||||
random16_add_entropy(random(256));
|
||||
|
||||
// Array of temperature readings at each simulation cell
|
||||
static byte heat[NUM_LEDS];
|
||||
|
||||
byte colorindex;
|
||||
|
||||
// Step 1. Cool down every cell a little
|
||||
for ( uint16_t i = 0; i < NUM_LEDS; i++) {
|
||||
heat[i] = qsub8( heat[i], random8(0, ((cooling * 10) / NUM_LEDS) + 2));
|
||||
}
|
||||
|
||||
// Step 2. Heat from each cell drifts 'up' and diffuses a little
|
||||
for ( uint16_t k = NUM_LEDS - 1; k >= 2; k--) {
|
||||
heat[k] = (heat[k - 1] + heat[k - 2] + heat[k - 2] ) / 3;
|
||||
}
|
||||
|
||||
// Step 3. Randomly ignite new 'sparks' of heat near the bottom
|
||||
if ( random8() < sparking ) {
|
||||
int y = random8(7);
|
||||
heat[y] = qadd8( heat[y], random8(160, 255) );
|
||||
}
|
||||
|
||||
// Step 4. Map from heat cells to LED colors
|
||||
for ( uint16_t j = 0; j < NUM_LEDS; j++) {
|
||||
// Scale the heat value from 0-255 down to 0-240
|
||||
// for best results with color palettes.
|
||||
colorindex = scale8(heat[j], 190);
|
||||
|
||||
CRGB color = ColorFromPalette(palette, colorindex);
|
||||
|
||||
if (up) {
|
||||
leds[j] = color;
|
||||
}
|
||||
else {
|
||||
leds[(NUM_LEDS - 1) - j] = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void fire()
|
||||
{
|
||||
heatMap(HeatColors_p, true);
|
||||
}
|
||||
|
||||
void water()
|
||||
{
|
||||
heatMap(IceColors_p, false);
|
||||
}
|
||||
|
||||
// Pride2015 by Mark Kriegsman: https://gist.github.com/kriegsman/964de772d64c502760e5
|
||||
// This function draws rainbows with an ever-changing,
|
||||
// widely-varying set of parameters.
|
||||
void pride()
|
||||
{
|
||||
static uint16_t sPseudotime = 0;
|
||||
static uint16_t sLastMillis = 0;
|
||||
static uint16_t sHue16 = 0;
|
||||
|
||||
uint8_t sat8 = beatsin88( 87, 220, 250);
|
||||
uint8_t brightdepth = beatsin88( 341, 96, 224);
|
||||
uint16_t brightnessthetainc16 = beatsin88( 203, (25 * 256), (40 * 256));
|
||||
uint8_t msmultiplier = beatsin88(147, 23, 60);
|
||||
|
||||
uint16_t hue16 = sHue16;//gHue * 256;
|
||||
uint16_t hueinc16 = beatsin88(113, 1, 3000);
|
||||
|
||||
uint16_t ms = millis();
|
||||
uint16_t deltams = ms - sLastMillis ;
|
||||
sLastMillis = ms;
|
||||
sPseudotime += deltams * msmultiplier;
|
||||
sHue16 += deltams * beatsin88( 400, 5, 9);
|
||||
uint16_t brightnesstheta16 = sPseudotime;
|
||||
|
||||
for ( uint16_t i = 0 ; i < NUM_LEDS; i++) {
|
||||
hue16 += hueinc16;
|
||||
uint8_t hue8 = hue16 / 256;
|
||||
|
||||
brightnesstheta16 += brightnessthetainc16;
|
||||
uint16_t b16 = sin16( brightnesstheta16 ) + 32768;
|
||||
|
||||
uint16_t bri16 = (uint32_t)((uint32_t)b16 * (uint32_t)b16) / 65536;
|
||||
uint8_t bri8 = (uint32_t)(((uint32_t)bri16) * brightdepth) / 65536;
|
||||
bri8 += (255 - brightdepth);
|
||||
|
||||
CRGB newcolor = CHSV( hue8, sat8, bri8);
|
||||
|
||||
uint16_t pixelnumber = i;
|
||||
pixelnumber = (NUM_LEDS - 1) - pixelnumber;
|
||||
|
||||
nblend( leds[pixelnumber], newcolor, 64);
|
||||
}
|
||||
}
|
||||
|
||||
// ColorWavesWithPalettes by Mark Kriegsman: https://gist.github.com/kriegsman/8281905786e8b2632aeb
|
||||
// This function draws color waves with an ever-changing,
|
||||
// widely-varying set of parameters, using a color palette.
|
||||
void colorwaves( CRGB* ledarray, uint16_t numleds, CRGBPalette16& palette)
|
||||
{
|
||||
static uint16_t sPseudotime = 0;
|
||||
static uint16_t sLastMillis = 0;
|
||||
static uint16_t sHue16 = 0;
|
||||
|
||||
// uint8_t sat8 = beatsin88( 87, 220, 250);
|
||||
uint8_t brightdepth = beatsin88( 341, 96, 224);
|
||||
uint16_t brightnessthetainc16 = beatsin88( 203, (25 * 256), (40 * 256));
|
||||
uint8_t msmultiplier = beatsin88(147, 23, 60);
|
||||
|
||||
uint16_t hue16 = sHue16;//gHue * 256;
|
||||
uint16_t hueinc16 = beatsin88(113, 300, 1500);
|
||||
|
||||
uint16_t ms = millis();
|
||||
uint16_t deltams = ms - sLastMillis ;
|
||||
sLastMillis = ms;
|
||||
sPseudotime += deltams * msmultiplier;
|
||||
sHue16 += deltams * beatsin88( 400, 5, 9);
|
||||
uint16_t brightnesstheta16 = sPseudotime;
|
||||
|
||||
for ( uint16_t i = 0 ; i < numleds; i++) {
|
||||
hue16 += hueinc16;
|
||||
uint8_t hue8 = hue16 / 256;
|
||||
uint16_t h16_128 = hue16 >> 7;
|
||||
if ( h16_128 & 0x100) {
|
||||
hue8 = 255 - (h16_128 >> 1);
|
||||
} else {
|
||||
hue8 = h16_128 >> 1;
|
||||
}
|
||||
|
||||
brightnesstheta16 += brightnessthetainc16;
|
||||
uint16_t b16 = sin16( brightnesstheta16 ) + 32768;
|
||||
|
||||
uint16_t bri16 = (uint32_t)((uint32_t)b16 * (uint32_t)b16) / 65536;
|
||||
uint8_t bri8 = (uint32_t)(((uint32_t)bri16) * brightdepth) / 65536;
|
||||
bri8 += (255 - brightdepth);
|
||||
|
||||
uint8_t index = hue8;
|
||||
//index = triwave8( index);
|
||||
index = scale8( index, 240);
|
||||
|
||||
CRGB newcolor = ColorFromPalette( palette, index, bri8);
|
||||
|
||||
uint16_t pixelnumber = i;
|
||||
pixelnumber = (numleds - 1) - pixelnumber;
|
||||
|
||||
nblend( ledarray[pixelnumber], newcolor, 128);
|
||||
}
|
||||
}
|
||||
|
||||
void colorWaves()
|
||||
{
|
||||
colorwaves(leds, NUM_LEDS, currentPalette);
|
||||
}
|
||||
|
||||
typedef void (*Pattern)();
|
||||
typedef Pattern PatternList[];
|
||||
typedef struct {
|
||||
Pattern pattern;
|
||||
String name;
|
||||
} PatternAndName;
|
||||
typedef PatternAndName PatternAndNameList[];
|
||||
|
||||
PatternAndNameList patterns = {
|
||||
{ pride, "Pride" },
|
||||
{ colorWaves, "Color Waves" },
|
||||
|
||||
// TwinkleFOX patterns
|
||||
{ drawTwinkles, "Twinkles" },
|
||||
|
||||
// Fire & Water
|
||||
{ fire, "Fire" },
|
||||
{ water, "Water" },
|
||||
|
||||
// DemoReel100 patterns
|
||||
{ rainbow, "rainbow" },
|
||||
{ rainbowWithGlitter, "rainbowWithGlitter" },
|
||||
{ confetti, "confetti" },
|
||||
{ sinelon, "sinelon" },
|
||||
{ juggle, "juggle" },
|
||||
{ bpm, "bpm" },
|
||||
|
||||
{ showSolidColor, "Solid Color" },
|
||||
};
|
||||
|
||||
const uint8_t patternCount = ARRAY_SIZE(patterns);
|
||||
205
src/studioledcam.ino
Normal file
205
src/studioledcam.ino
Normal file
@ -0,0 +1,205 @@
|
||||
/*
|
||||
ESP32 FastLED WebServer: https://github.com/jasoncoon/esp32-fastled-webserver
|
||||
Copyright (C) 2017 Jason Coon
|
||||
|
||||
Built upon the amazing FastLED work of Daniel Garcia and Mark Kriegsman:
|
||||
https://github.com/FastLED/FastLED
|
||||
|
||||
ESP32 support provided by the hard work of Sam Guyer:
|
||||
https://github.com/samguyer/FastLED
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <FastLED.h>
|
||||
#include <WiFi.h>
|
||||
#include <WebServer.h>
|
||||
#include <FS.h>
|
||||
#include <SPIFFS.h>
|
||||
#include <EEPROM.h>
|
||||
|
||||
#if defined(FASTLED_VERSION) && (FASTLED_VERSION < 3003000)
|
||||
#warning "Requires FastLED 3.3 or later; check github for latest code."
|
||||
#endif
|
||||
|
||||
WebServer webServer(80);
|
||||
|
||||
const int led = 5;
|
||||
|
||||
uint8_t autoplay = 0;
|
||||
uint8_t autoplayDuration = 10;
|
||||
unsigned long autoPlayTimeout = 0;
|
||||
|
||||
uint8_t currentPatternIndex = 0; // Index number of which pattern is current
|
||||
|
||||
uint8_t gHue = 0; // rotating "base color" used by many of the patterns
|
||||
|
||||
uint8_t power = 1;
|
||||
uint8_t brightness = 8;
|
||||
|
||||
uint8_t speed = 30;
|
||||
|
||||
// COOLING: How much does the air cool as it rises?
|
||||
// Less cooling = taller flames. More cooling = shorter flames.
|
||||
// Default 50, suggested range 20-100
|
||||
uint8_t cooling = 50;
|
||||
|
||||
// SPARKING: What chance (out of 255) is there that a new spark will be lit?
|
||||
// Higher chance = more roaring fire. Lower chance = more flickery fire.
|
||||
// Default 120, suggested range 50-200.
|
||||
uint8_t sparking = 120;
|
||||
|
||||
CRGB solidColor = CRGB::Blue;
|
||||
|
||||
uint8_t cyclePalettes = 0;
|
||||
uint8_t paletteDuration = 10;
|
||||
uint8_t currentPaletteIndex = 0;
|
||||
unsigned long paletteTimeout = 0;
|
||||
|
||||
#define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0]))
|
||||
|
||||
#define LED_TYPE WS2812B
|
||||
#define COLOR_ORDER GRB
|
||||
#define NUM_STRIPS 4
|
||||
#define NUM_LEDS_PER_STRIP 16
|
||||
#define NUM_LEDS NUM_LEDS_PER_STRIP * NUM_STRIPS
|
||||
CRGB leds[NUM_LEDS];
|
||||
|
||||
#define MILLI_AMPS 4000 // IMPORTANT: set the max milli-Amps of your power supply (4A = 4000mA)
|
||||
#define FRAMES_PER_SECOND 120
|
||||
|
||||
#include "patterns.h"
|
||||
|
||||
#include "field.h"
|
||||
#include "fields.h"
|
||||
|
||||
#include "secrets.h"
|
||||
#include "wifi.h"
|
||||
#include "web.h"
|
||||
|
||||
// wifi ssid and password should be added to a file in the sketch named secrets.h
|
||||
// the secrets.h file should be added to the .gitignore file and never committed or
|
||||
// pushed to public source control (GitHub).
|
||||
// const char* ssid = "........";
|
||||
// const char* password = "........";
|
||||
|
||||
void listDir(fs::FS &fs, const char * dirname, uint8_t levels) {
|
||||
Serial.printf("Listing directory: %s\n", dirname);
|
||||
|
||||
File root = fs.open(dirname);
|
||||
if (!root) {
|
||||
Serial.println("Failed to open directory");
|
||||
return;
|
||||
}
|
||||
if (!root.isDirectory()) {
|
||||
Serial.println("Not a directory");
|
||||
return;
|
||||
}
|
||||
|
||||
File file = root.openNextFile();
|
||||
while (file) {
|
||||
if (file.isDirectory()) {
|
||||
Serial.print(" DIR : ");
|
||||
Serial.println(file.name());
|
||||
if (levels) {
|
||||
listDir(fs, file.name(), levels - 1);
|
||||
}
|
||||
} else {
|
||||
Serial.print(" FILE: ");
|
||||
Serial.print(file.name());
|
||||
Serial.print(" SIZE: ");
|
||||
Serial.println(file.size());
|
||||
}
|
||||
file = root.openNextFile();
|
||||
}
|
||||
}
|
||||
|
||||
void setup() {
|
||||
pinMode(led, OUTPUT);
|
||||
digitalWrite(led, 1);
|
||||
|
||||
// delay(3000); // 3 second delay for recovery
|
||||
Serial.begin(115200);
|
||||
|
||||
SPIFFS.begin();
|
||||
listDir(SPIFFS, "/", 1);
|
||||
|
||||
// loadFieldsFromEEPROM(fields, fieldCount);
|
||||
|
||||
setupWifi();
|
||||
setupWeb();
|
||||
|
||||
|
||||
// Parallel output: 13, 12, 15, 14,
|
||||
FastLED.addLeds<LED_TYPE, 13, COLOR_ORDER>(leds, 0, NUM_LEDS_PER_STRIP).setCorrection(TypicalLEDStrip);
|
||||
FastLED.addLeds<LED_TYPE, 12, COLOR_ORDER>(leds, NUM_LEDS_PER_STRIP, NUM_LEDS_PER_STRIP).setCorrection(TypicalLEDStrip);
|
||||
FastLED.addLeds<LED_TYPE, 15, COLOR_ORDER>(leds, 2 * NUM_LEDS_PER_STRIP, NUM_LEDS_PER_STRIP).setCorrection(TypicalLEDStrip);
|
||||
FastLED.addLeds<LED_TYPE, 14, COLOR_ORDER>(leds, 3 * NUM_LEDS_PER_STRIP, NUM_LEDS_PER_STRIP).setCorrection(TypicalLEDStrip);
|
||||
|
||||
|
||||
FastLED.setMaxPowerInVoltsAndMilliamps(5, MILLI_AMPS);
|
||||
|
||||
// set master brightness control
|
||||
FastLED.setBrightness(brightness);
|
||||
|
||||
autoPlayTimeout = millis() + (autoplayDuration * 1000);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
handleWeb();
|
||||
|
||||
if (power == 0) {
|
||||
fill_solid(leds, NUM_LEDS, CRGB::Black);
|
||||
}
|
||||
else {
|
||||
// Call the current pattern function once, updating the 'leds' array
|
||||
patterns[currentPatternIndex].pattern();
|
||||
|
||||
EVERY_N_MILLISECONDS(40) {
|
||||
// slowly blend the current palette to the next
|
||||
nblendPaletteTowardPalette(currentPalette, targetPalette, 8);
|
||||
gHue++; // slowly cycle the "base color" through the rainbow
|
||||
}
|
||||
|
||||
if (autoplay == 1 && (millis() > autoPlayTimeout)) {
|
||||
nextPattern();
|
||||
autoPlayTimeout = millis() + (autoplayDuration * 1000);
|
||||
}
|
||||
|
||||
if (cyclePalettes == 1 && (millis() > paletteTimeout)) {
|
||||
nextPalette();
|
||||
paletteTimeout = millis() + (paletteDuration * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
// send the 'leds' array out to the actual LED strip
|
||||
FastLED.show();
|
||||
|
||||
// insert a delay to keep the framerate modest
|
||||
// FastLED.delay(1000 / FRAMES_PER_SECOND);
|
||||
delay(1000 / FRAMES_PER_SECOND);
|
||||
}
|
||||
|
||||
void nextPattern()
|
||||
{
|
||||
// add one to the current pattern number, and wrap around at the end
|
||||
currentPatternIndex = (currentPatternIndex + 1) % patternCount;
|
||||
}
|
||||
|
||||
void nextPalette()
|
||||
{
|
||||
currentPaletteIndex = (currentPaletteIndex + 1) % paletteCount;
|
||||
targetPalette = palettes[currentPaletteIndex];
|
||||
}
|
||||
229
src/twinkleFox.h
Normal file
229
src/twinkleFox.h
Normal file
@ -0,0 +1,229 @@
|
||||
// TwinkleFOX by Mark Kriegsman: https://gist.github.com/kriegsman/756ea6dcae8e30845b5a
|
||||
//
|
||||
// TwinkleFOX: Twinkling 'holiday' lights that fade in and out.
|
||||
// Colors are chosen from a palette; a few palettes are provided.
|
||||
//
|
||||
// This December 2015 implementation improves on the December 2014 version
|
||||
// in several ways:
|
||||
// - smoother fading, compatible with any colors and any palettes
|
||||
// - easier control of twinkle speed and twinkle density
|
||||
// - supports an optional 'background color'
|
||||
// - takes even less RAM: zero RAM overhead per pixel
|
||||
// - illustrates a couple of interesting techniques (uh oh...)
|
||||
//
|
||||
// The idea behind this (new) implementation is that there's one
|
||||
// basic, repeating pattern that each pixel follows like a waveform:
|
||||
// The brightness rises from 0..255 and then falls back down to 0.
|
||||
// The brightness at any given point in time can be determined as
|
||||
// as a function of time, for example:
|
||||
// brightness = sine( time ); // a sine wave of brightness over time
|
||||
//
|
||||
// So the way this implementation works is that every pixel follows
|
||||
// the exact same wave function over time. In this particular case,
|
||||
// I chose a sawtooth triangle wave (triwave8) rather than a sine wave,
|
||||
// but the idea is the same: brightness = triwave8( time ).
|
||||
//
|
||||
// Of course, if all the pixels used the exact same wave form, and
|
||||
// if they all used the exact same 'clock' for their 'time base', all
|
||||
// the pixels would brighten and dim at once -- which does not look
|
||||
// like twinkling at all.
|
||||
//
|
||||
// So to achieve random-looking twinkling, each pixel is given a
|
||||
// slightly different 'clock' signal. Some of the clocks run faster,
|
||||
// some run slower, and each 'clock' also has a random offset from zero.
|
||||
// The net result is that the 'clocks' for all the pixels are always out
|
||||
// of sync from each other, producing a nice random distribution
|
||||
// of twinkles.
|
||||
//
|
||||
// The 'clock speed adjustment' and 'time offset' for each pixel
|
||||
// are generated randomly. One (normal) approach to implementing that
|
||||
// would be to randomly generate the clock parameters for each pixel
|
||||
// at startup, and store them in some arrays. However, that consumes
|
||||
// a great deal of precious RAM, and it turns out to be totally
|
||||
// unnessary! If the random number generate is 'seeded' with the
|
||||
// same starting value every time, it will generate the same sequence
|
||||
// of values every time. So the clock adjustment parameters for each
|
||||
// pixel are 'stored' in a pseudo-random number generator! The PRNG
|
||||
// is reset, and then the first numbers out of it are the clock
|
||||
// adjustment parameters for the first pixel, the second numbers out
|
||||
// of it are the parameters for the second pixel, and so on.
|
||||
// In this way, we can 'store' a stable sequence of thousands of
|
||||
// random clock adjustment parameters in literally two bytes of RAM.
|
||||
//
|
||||
// There's a little bit of fixed-point math involved in applying the
|
||||
// clock speed adjustments, which are expressed in eighths. Each pixel's
|
||||
// clock speed ranges from 8/8ths of the system clock (i.e. 1x) to
|
||||
// 23/8ths of the system clock (i.e. nearly 3x).
|
||||
//
|
||||
// On a basic Arduino Uno or Leonardo, this code can twinkle 300+ pixels
|
||||
// smoothly at over 50 updates per seond.
|
||||
//
|
||||
// -Mark Kriegsman, December 2015
|
||||
|
||||
// Overall twinkle speed.
|
||||
// 0 (VERY slow) to 8 (VERY fast).
|
||||
// 4, 5, and 6 are recommended, default is 4.
|
||||
uint8_t twinkleSpeed = 4;
|
||||
|
||||
// Overall twinkle density.
|
||||
// 0 (NONE lit) to 8 (ALL lit at once).
|
||||
// Default is 5.
|
||||
uint8_t twinkleDensity = 5;
|
||||
|
||||
// Background color for 'unlit' pixels
|
||||
// Can be set to CRGB::Black if desired.
|
||||
CRGB gBackgroundColor = CRGB::Black;
|
||||
// Example of dim incandescent fairy light background color
|
||||
// CRGB gBackgroundColor = CRGB(CRGB::FairyLight).nscale8_video(16);
|
||||
|
||||
// If AUTO_SELECT_BACKGROUND_COLOR is set to 1,
|
||||
// then for any palette where the first two entries
|
||||
// are the same, a dimmed version of that color will
|
||||
// automatically be used as the background color.
|
||||
#define AUTO_SELECT_BACKGROUND_COLOR 0
|
||||
|
||||
// If COOL_LIKE_INCANDESCENT is set to 1, colors will
|
||||
// fade out slighted 'reddened', similar to how
|
||||
// incandescent bulbs change color as they get dim down.
|
||||
#define COOL_LIKE_INCANDESCENT 1
|
||||
|
||||
// This function is like 'triwave8', which produces a
|
||||
// symmetrical up-and-down triangle sawtooth waveform, except that this
|
||||
// function produces a triangle wave with a faster attack and a slower decay:
|
||||
//
|
||||
// / \__
|
||||
// / \__
|
||||
// / \__
|
||||
// / \__
|
||||
//
|
||||
|
||||
uint8_t attackDecayWave8( uint8_t i)
|
||||
{
|
||||
if( i < 86) {
|
||||
return i * 3;
|
||||
} else {
|
||||
i -= 86;
|
||||
return 255 - (i + (i/2));
|
||||
}
|
||||
}
|
||||
|
||||
// This function takes a pixel, and if its in the 'fading down'
|
||||
// part of the cycle, it adjusts the color a little bit like the
|
||||
// way that incandescent bulbs fade toward 'red' as they dim.
|
||||
void coolLikeIncandescent( CRGB& c, uint8_t phase)
|
||||
{
|
||||
if( phase < 128) return;
|
||||
|
||||
uint8_t cooling = (phase - 128) >> 4;
|
||||
c.g = qsub8( c.g, cooling);
|
||||
c.b = qsub8( c.b, cooling * 2);
|
||||
}
|
||||
|
||||
// This function takes a time in pseudo-milliseconds,
|
||||
// figures out brightness = f( time ), and also hue = f( time )
|
||||
// The 'low digits' of the millisecond time are used as
|
||||
// input to the brightness wave function.
|
||||
// The 'high digits' are used to select a color, so that the color
|
||||
// does not change over the course of the fade-in, fade-out
|
||||
// of one cycle of the brightness wave function.
|
||||
// The 'high digits' are also used to determine whether this pixel
|
||||
// should light at all during this cycle, based on the twinkleDensity.
|
||||
CRGB computeOneTwinkle( uint32_t ms, uint8_t salt)
|
||||
{
|
||||
uint16_t ticks = ms >> (8-twinkleSpeed);
|
||||
uint8_t fastcycle8 = ticks;
|
||||
uint16_t slowcycle16 = (ticks >> 8) + salt;
|
||||
slowcycle16 += sin8( slowcycle16);
|
||||
slowcycle16 = (slowcycle16 * 2053) + 1384;
|
||||
uint8_t slowcycle8 = (slowcycle16 & 0xFF) + (slowcycle16 >> 8);
|
||||
|
||||
uint8_t bright = 0;
|
||||
if( ((slowcycle8 & 0x0E)/2) < twinkleDensity) {
|
||||
bright = attackDecayWave8( fastcycle8);
|
||||
}
|
||||
|
||||
uint8_t hue = slowcycle8 - salt;
|
||||
CRGB c;
|
||||
if( bright > 0) {
|
||||
c = ColorFromPalette( palettes[currentPaletteIndex], hue, bright, NOBLEND);
|
||||
if( COOL_LIKE_INCANDESCENT == 1 ) {
|
||||
coolLikeIncandescent( c, fastcycle8);
|
||||
}
|
||||
} else {
|
||||
c = CRGB::Black;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
// This function loops over each pixel, calculates the
|
||||
// adjusted 'clock' that this pixel should use, and calls
|
||||
// "CalculateOneTwinkle" on each pixel. It then displays
|
||||
// either the twinkle color of the background color,
|
||||
// whichever is brighter.
|
||||
void drawTwinkles()
|
||||
{
|
||||
// "PRNG16" is the pseudorandom number generator
|
||||
// It MUST be reset to the same starting value each time
|
||||
// this function is called, so that the sequence of 'random'
|
||||
// numbers that it generates is (paradoxically) stable.
|
||||
uint16_t PRNG16 = 11337;
|
||||
|
||||
uint32_t clock32 = millis();
|
||||
|
||||
CRGBPalette16 currentPalette = palettes[currentPaletteIndex];
|
||||
|
||||
// Set up the background color, "bg".
|
||||
// if AUTO_SELECT_BACKGROUND_COLOR == 1, and the first two colors of
|
||||
// the current palette are identical, then a deeply faded version of
|
||||
// that color is used for the background color
|
||||
CRGB bg;
|
||||
if( (AUTO_SELECT_BACKGROUND_COLOR == 1) &&
|
||||
(currentPalette[0] == currentPalette[1] )) {
|
||||
bg = currentPalette[0];
|
||||
uint8_t bglight = bg.getAverageLight();
|
||||
if( bglight > 64) {
|
||||
bg.nscale8_video( 16); // very bright, so scale to 1/16th
|
||||
} else if( bglight > 16) {
|
||||
bg.nscale8_video( 64); // not that bright, so scale to 1/4th
|
||||
} else {
|
||||
bg.nscale8_video( 86); // dim, scale to 1/3rd.
|
||||
}
|
||||
} else {
|
||||
bg = gBackgroundColor; // just use the explicitly defined background color
|
||||
}
|
||||
|
||||
uint8_t backgroundBrightness = bg.getAverageLight();
|
||||
|
||||
for(uint16_t i = 0; i < NUM_LEDS; i++) {
|
||||
CRGB& pixel = leds[i];
|
||||
|
||||
PRNG16 = (uint16_t)(PRNG16 * 2053) + 1384; // next 'random' number
|
||||
uint16_t myclockoffset16= PRNG16; // use that number as clock offset
|
||||
PRNG16 = (uint16_t)(PRNG16 * 2053) + 1384; // next 'random' number
|
||||
// use that number as clock speed adjustment factor (in 8ths, from 8/8ths to 23/8ths)
|
||||
uint8_t myspeedmultiplierQ5_3 = ((((PRNG16 & 0xFF)>>4) + (PRNG16 & 0x0F)) & 0x0F) + 0x08;
|
||||
uint32_t myclock30 = (uint32_t)((clock32 * myspeedmultiplierQ5_3) >> 3) + myclockoffset16;
|
||||
uint8_t myunique8 = PRNG16 >> 8; // get 'salt' value for this pixel
|
||||
|
||||
// We now have the adjusted 'clock' for this pixel, now we call
|
||||
// the function that computes what color the pixel should be based
|
||||
// on the "brightness = f( time )" idea.
|
||||
CRGB c = computeOneTwinkle( myclock30, myunique8);
|
||||
|
||||
uint8_t cbright = c.getAverageLight();
|
||||
int16_t deltabright = cbright - backgroundBrightness;
|
||||
if( deltabright >= 32 || (!bg)) {
|
||||
// If the new pixel is significantly brighter than the background color,
|
||||
// use the new color.
|
||||
pixel = c;
|
||||
} else if( deltabright > 0 ) {
|
||||
// If the new pixel is just slightly brighter than the background color,
|
||||
// mix a blend of the new color and the background color
|
||||
pixel = blend( bg, c, deltabright * 8);
|
||||
} else {
|
||||
// if the new pixel is not at all brighter than the background color,
|
||||
// just use the background color.
|
||||
pixel = bg;
|
||||
}
|
||||
}
|
||||
}
|
||||
87
src/web.h
Normal file
87
src/web.h
Normal file
@ -0,0 +1,87 @@
|
||||
/*
|
||||
ESP32 FastLED WebServer: https://github.com/jasoncoon/esp32-fastled-webserver
|
||||
Copyright (C) 2017 Jason Coon
|
||||
|
||||
Built upon the amazing FastLED work of Daniel Garcia and Mark Kriegsman:
|
||||
https://github.com/FastLED/FastLED
|
||||
|
||||
ESP32 support provided by the hard work of Sam Guyer:
|
||||
https://github.com/samguyer/FastLED
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
void setupWeb() {
|
||||
webServer.on("/all", HTTP_GET, []() {
|
||||
digitalWrite(led, 0);
|
||||
String json = getFieldsJson(fields, fieldCount);
|
||||
webServer.send(200, "text/json", json);
|
||||
digitalWrite(led, 1);
|
||||
});
|
||||
|
||||
webServer.on("/fieldValue", HTTP_GET, []() {
|
||||
digitalWrite(led, 0);
|
||||
String name = webServer.arg("name");
|
||||
String value = getFieldValue(name, fields, fieldCount);
|
||||
webServer.send(200, "text/json", value);
|
||||
digitalWrite(led, 1);
|
||||
});
|
||||
|
||||
webServer.on("/fieldValue", HTTP_POST, []() {
|
||||
digitalWrite(led, 0);
|
||||
String name = webServer.arg("name");
|
||||
String value = webServer.arg("value");
|
||||
String newValue = setFieldValue(name, value, fields, fieldCount);
|
||||
webServer.send(200, "text/json", newValue);
|
||||
digitalWrite(led, 1);
|
||||
});
|
||||
|
||||
webServer.serveStatic("/", SPIFFS, "/index.htm", "max-age=86400");
|
||||
webServer.serveStatic("/index.htm", SPIFFS, "/index.htm", "max-age=86400");
|
||||
webServer.serveStatic("/favicon.ico", SPIFFS, "/favicon.ico", "max-age=86400");
|
||||
webServer.serveStatic("/css/styles.css", SPIFFS, "/css/styles.css", "max-age=86400");
|
||||
webServer.serveStatic("/js/app.js", SPIFFS, "/js/app.js", "max-age=86400");
|
||||
webServer.serveStatic("/images/atom196.png", SPIFFS, "/images/atom196.png", "max-age=86400");
|
||||
|
||||
webServer.begin();
|
||||
Serial.println ( "HTTP server started" );
|
||||
}
|
||||
|
||||
void handleWeb() {
|
||||
static bool webServerStarted = false;
|
||||
|
||||
// check for connection
|
||||
if ( WiFi.status() == WL_CONNECTED ) {
|
||||
if (!webServerStarted) {
|
||||
// turn off the board's LED when connected to wifi
|
||||
digitalWrite(led, 1);
|
||||
Serial.println();
|
||||
Serial.println("WiFi connected");
|
||||
Serial.print("IP address: ");
|
||||
Serial.println(WiFi.localIP());
|
||||
webServerStarted = true;
|
||||
setupWeb();
|
||||
}
|
||||
webServer.handleClient();
|
||||
} else {
|
||||
// blink the board's LED while connecting to wifi
|
||||
static uint8_t ledState = 0;
|
||||
EVERY_N_MILLIS(125) {
|
||||
ledState = ledState == 0 ? 1 : 0;
|
||||
digitalWrite(led, ledState);
|
||||
Serial.print (".");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
68
src/wifi.h
Normal file
68
src/wifi.h
Normal file
@ -0,0 +1,68 @@
|
||||
/*
|
||||
ESP32 FastLED WebServer: https://github.com/jasoncoon/esp32-fastled-webserver
|
||||
Copyright (C) 2017 Jason Coon
|
||||
|
||||
Built upon the amazing FastLED work of Daniel Garcia and Mark Kriegsman:
|
||||
https://github.com/FastLED/FastLED
|
||||
|
||||
ESP32 support provided by the hard work of Sam Guyer:
|
||||
https://github.com/samguyer/FastLED
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
//#define HOSTNAME "ESP32-" ///< Hostname. The setup function adds the Chip ID at the end.
|
||||
|
||||
//const bool apMode = false;
|
||||
|
||||
// AP mode password
|
||||
//const char WiFiAPPSK[] = "";
|
||||
|
||||
void setupWifi() {
|
||||
// // Set Hostname.
|
||||
// String hostname(HOSTNAME);
|
||||
//
|
||||
// uint64_t chipid = ESP.getEfuseMac();
|
||||
// uint16_t long1 = (unsigned long)((chipid & 0xFFFF0000) >> 16 );
|
||||
// uint16_t long2 = (unsigned long)((chipid & 0x0000FFFF));
|
||||
// String hex = String(long1, HEX) + String(long2, HEX); // six octets
|
||||
// hostname += hex;
|
||||
//
|
||||
// char hostnameChar[hostname.length() + 1];
|
||||
// memset(hostnameChar, 0, hostname.length() + 1);
|
||||
//
|
||||
// for (uint8_t i = 0; i < hostname.length(); i++)
|
||||
// hostnameChar[i] = hostname.charAt(i);
|
||||
//
|
||||
// WiFi.setHostname(hostnameChar);
|
||||
//
|
||||
// // Print hostname.
|
||||
// Serial.println("Hostname: " + hostname);
|
||||
|
||||
// if (apMode)
|
||||
// {
|
||||
// WiFi.mode(WIFI_AP);
|
||||
// WiFi.softAP(hostnameChar, WiFiAPPSK);
|
||||
// Serial.printf("Connect to Wi-Fi access point: %s\n", hostnameChar);
|
||||
// Serial.println("and open http://192.168.4.1 in your browser");
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
WiFi.mode(WIFI_STA);
|
||||
Serial.printf("Connecting to %s\n", ssid);
|
||||
if (String(WiFi.SSID()) != String(ssid)) {
|
||||
WiFi.begin(ssid, password);
|
||||
}
|
||||
// }
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user