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