Merge pull request #81 from FabLab-Luenen/development

Development
This commit is contained in:
bpohvoodoo
2020-04-18 09:14:23 +02:00
committed by GitHub
25 changed files with 2947 additions and 8364 deletions
-6
View File
@@ -1,6 +0,0 @@
[submodule "Arduino/McLighting/data/McLightingUI"]
path = Arduino/McLighting/data/McLightingUI
url = https://github.com/toblum/McLightingUI
[submodule "clients/web/McLightingUI"]
path = clients/web/McLightingUI
url = https://github.com/toblum/McLightingUI
+1 -1
View File
@@ -747,7 +747,7 @@ void loop() {
#endif #endif
#if defined(ENABLE_HOMEASSISTANT) #if defined(ENABLE_HOMEASSISTANT)
if(ha_send_data.active()) ha_send_data.detach(); if(ha_send_data.active()) ha_send_data.detach();
ha_send_data.once(5, tickerSendState); ha_send_data.once(DELAY_MQTT_HA_MESSAGE, tickerSendState);
#endif #endif
#endif #endif
} }
+3 -3
View File
@@ -20,7 +20,7 @@ char HOSTNAME[65] = "McLightingRGBW"; // Friedly hostname is configurable just
//#define ENABLE_MQTT_INCLUDE_IP // uncomment/comment to add the IP-adress to the MQTT message //#define ENABLE_MQTT_INCLUDE_IP // uncomment/comment to add the IP-adress to the MQTT message
#define ENABLE_HOMEASSISTANT // If defined, enable Homeassistant integration, ENABLE_MQTT must be active #define ENABLE_HOMEASSISTANT // If defined, enable Homeassistant integration, ENABLE_MQTT must be active
#define MQTT_HOME_ASSISTANT_SUPPORT // If defined, use AMQTT and select Tools -> IwIP Variant -> Higher Bandwidth #define MQTT_HOME_ASSISTANT_SUPPORT // If defined, use AMQTT and select Tools -> IwIP Variant -> Higher Bandwidth
//#define DISABLE_MQTT_OUT_ON_MQTT_IN // If defined, McLighting will not send back MQTT-out on MQTT-in regarding issue #67, does not change anything at the moment #define DELAY_MQTT_HA_MESSAGE 5 // HA Status is send after DELAY_MQTT_HA_MESSAGE seconds, to save bandwith
//#define ENABLE_BUTTON 14 // If defined, enable button handling code, see: https://github.com/toblum/McLighting/wiki/Button-control, the value defines the input pin (14 / D5) for switching the LED strip on / off, connect this PIN to ground to trigger button. //#define ENABLE_BUTTON 14 // If defined, enable button handling code, see: https://github.com/toblum/McLighting/wiki/Button-control, the value defines the input pin (14 / D5) for switching the LED strip on / off, connect this PIN to ground to trigger button.
//#define ENABLE_BUTTON_GY33 12 // If defined, enable button handling code for GY-33 color sensor to scan color. The value defines the input pin (12 / D6) for read color data with RGB sensor, connect this PIN to ground to trigger button. //#define ENABLE_BUTTON_GY33 12 // If defined, enable button handling code for GY-33 color sensor to scan color. The value defines the input pin (12 / D6) for read color data with RGB sensor, connect this PIN to ground to trigger button.
@@ -178,10 +178,10 @@ struct {
uint8_t pin = 3; uint8_t pin = 3;
#endif #endif
#if USE_WS2812FX_DMA == 1 #if USE_WS2812FX_DMA == 1
uint8_t pin = 2; uint8_t pin = 1;
#endif #endif
#if USE_WS2812FX_DMA == 2 #if USE_WS2812FX_DMA == 2
uint8_t pin = 1; uint8_t pin = 2;
#endif #endif
#else #else
uint8_t pin = LED_PIN; uint8_t pin = LED_PIN;
-77
View File
@@ -1,77 +0,0 @@
// ***************************************************************************
// TV mode
// ***************************************************************************
uint8_t dipInterval = 10;
uint16_t darkTime = 250;
unsigned long currentDipTime;
unsigned long dipStartTime;
unsigned long currentMillis;
uint8_t ledState = LOW;
long previousMillis = 0;
uint16_t led = 5;
uint16_t interv = 2000;
uint8_t twitch = 50;
uint8_t dipCount = 0;
uint8_t analogLevel = 100;
boolean timeToDip = false;
void hsb2rgbAN1(uint16_t index, uint8_t sat, uint8_t bright, uint8_t myled) {
// Source: https://blog.adafruit.com/2012/03/14/constant-brightness-hsb-to-rgb-algorithm/
uint8_t temp[5], n = (index >> 8) % 3;
temp[0] = temp[3] = (uint8_t)(( (sat ^ 255) * bright) / 255);
temp[1] = temp[4] = (uint8_t)((((( (index & 255) * sat) / 255) + (sat ^ 255)) * bright) / 255);
temp[2] = (uint8_t)(((((((index & 255) ^ 255) * sat) / 255) + (sat ^ 255)) * bright) / 255);
strip->setPixelColor(myled, temp[n + 2], temp[n + 1], temp[n], 0);
}
void updateLed (uint16_t led, uint8_t brightness) {
ledstates[led] = brightness;
for (uint16_t i=0; i<WS2812FXStripSettings.stripSize; i++) {
uint16_t index = (i%3 == 0) ? 400 : random(0,767);
hsb2rgbAN1(index, 200, ledstates[i], i);
}
strip->show();
}
// See: http://forum.mysensors.org/topic/85/phoneytv-for-vera-is-here/13
void handleTV() {
if (timeToDip == false) {
currentMillis = millis();
if(currentMillis-previousMillis > interv) {
previousMillis = currentMillis;
//interv = random(750,4001);//Adjusts the interval for more/less frequent random light changes
interv = random(1000-(ws2812fx_speed*2),5001-(ws2812fx_speed*8));
twitch = random(40,100);// Twitch provides motion effect but can be a bit much if too high
dipCount = dipCount++;
}
if(currentMillis-previousMillis<twitch) {
led=random(0, WS2812FXStripSettings.stripSize - 1);
analogLevel=random(50,255);// set the range of the 3 pwm leds
ledState = ledState == LOW ? HIGH: LOW; // if the LED is off turn it on and vice-versa:
updateLed(led, (ledState) ? 255 : 0);
if (dipCount > dipInterval) {
DBG_OUTPUT_PORT.println("dip");
timeToDip = true;
dipCount = 0;
dipStartTime = millis();
darkTime = random(50,150);
dipInterval = random(5,250);// cycles of flicker
}
}
} else {
DBG_OUTPUT_PORT.println("Dip Time");
currentDipTime = millis();
if (currentDipTime - dipStartTime < darkTime) {
for (uint16_t i=3; i<WS2812FXStripSettings.stripSize; i++) {
updateLed(i, 0);
}
} else {
timeToDip = false;
}
//strip->show();
}
}
+8 -4
View File
@@ -743,11 +743,15 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t lenght
root["effect"] = strip->getModeName(strip->getMode()); root["effect"] = strip->getModeName(strip->getMode());
} }
#endif #endif
char buffer[measureJson(root) + 1]; uint16_t msg_len = measureJson(root) + 1;
char buffer[msg_len];
serializeJson(root, buffer, sizeof(buffer)); serializeJson(root, buffer, sizeof(buffer));
jsonBuffer.clear(); jsonBuffer.clear();
#if ENABLE_MQTT == 0 #if ENABLE_MQTT == 0
mqtt_client->publish(mqtt_ha_state_out, buffer, true); //mqtt_client->publish(mqtt_ha_state_out, buffer, true);
mqtt_client->beginPublish(mqtt_ha_state_out, msg_len-1, true);
mqtt_client->write((const uint8_t*)buffer, msg_len-1);
mqtt_client->endPublish();
DBG_OUTPUT_PORT.printf("MQTT: Send [%s]: %s\r\n", mqtt_ha_state_out, buffer); DBG_OUTPUT_PORT.printf("MQTT: Send [%s]: %s\r\n", mqtt_ha_state_out, buffer);
#endif #endif
#if ENABLE_MQTT == 1 #if ENABLE_MQTT == 1
@@ -901,7 +905,7 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t lenght
return; return;
} }
if(ha_send_data.active()) ha_send_data.detach(); if(ha_send_data.active()) ha_send_data.detach();
ha_send_data.once(5, tickerSendState); ha_send_data.once(DELAY_MQTT_HA_MESSAGE, tickerSendState);
} else if (strcmp(topic, mqtt_intopic) == 0) { } else if (strcmp(topic, mqtt_intopic) == 0) {
#endif #endif
@@ -936,7 +940,7 @@ void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t lenght
#if defined(ENABLE_HOMEASSISTANT) #if defined(ENABLE_HOMEASSISTANT)
ha_send_data.detach(); ha_send_data.detach();
mqtt_client->subscribe(mqtt_ha_state_in, qossub); mqtt_client->subscribe(mqtt_ha_state_in, qossub);
ha_send_data.once(5, tickerSendState); ha_send_data.once(DELAY_MQTT_HA_MESSAGE, tickerSendState);
#if defined(MQTT_HOME_ASSISTANT_SUPPORT) #if defined(MQTT_HOME_ASSISTANT_SUPPORT)
const size_t bufferSize = JSON_ARRAY_SIZE(strip->getModeCount()+ 4) + JSON_OBJECT_SIZE(11) + 1500; const size_t bufferSize = JSON_ARRAY_SIZE(strip->getModeCount()+ 4) + JSON_OBJECT_SIZE(11) + 1500;
DynamicJsonDocument jsonBuffer(bufferSize); DynamicJsonDocument jsonBuffer(bufferSize);
+1 -1
View File
@@ -1 +1 @@
#define SKETCH_VERSION "3.1.0" #define SKETCH_VERSION "3.1.1"
+4
View File
@@ -257,4 +257,8 @@
* Version Bump to 3.1.0 * Version Bump to 3.1.0
* bugfixes * bugfixes
* E1.31 is now working for multi segments * E1.31 is now working for multi segments
*
* 18 April 2020
* Version Bump to 3.1.1
* bugfixes regarding issue #80
*/ */
-674
View File
@@ -1,674 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>SPIFFS Editor</title>
<style type="text/css" media="screen">
.contextMenu {
z-index: 300;
position: absolute;
left: 5px;
border: 1px solid #444;
background-color: #F5F5F5;
display: none;
box-shadow: 0 0 10px rgba( 0, 0, 0, .4 );
font-size: 12px;
font-family: sans-serif;
font-weight:bold;
}
.contextMenu ul {
list-style: none;
top: 0;
left: 0;
margin: 0;
padding: 0;
}
.contextMenu li {
position: relative;
min-width: 60px;
cursor: pointer;
}
.contextMenu span {
color: #444;
display: inline-block;
padding: 6px;
}
.contextMenu li:hover { background: #444; }
.contextMenu li:hover span { color: #EEE; }
.css-treeview ul, .css-treeview li {
padding: 0;
margin: 0;
list-style: none;
}
.css-treeview input {
position: absolute;
opacity: 0;
}
.css-treeview {
font: normal 11px Verdana, Arial, Sans-serif;
-moz-user-select: none;
-webkit-user-select: none;
user-select: none;
}
.css-treeview span {
color: #00f;
cursor: pointer;
}
.css-treeview span:hover {
text-decoration: underline;
}
.css-treeview input + label + ul {
margin: 0 0 0 22px;
}
.css-treeview input ~ ul {
display: none;
}
.css-treeview label, .css-treeview label::before {
cursor: pointer;
}
.css-treeview input:disabled + label {
cursor: default;
opacity: .6;
}
.css-treeview input:checked:not(:disabled) ~ ul {
display: block;
}
.css-treeview label, .css-treeview label::before {
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAACgCAYAAAAFOewUAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAApxJREFUeNrslM1u00AQgGdthyalFFOK+ClIIKQKyqUVQvTEE3DmAhLwAhU8QZoH4A2Q2gMSFace4MCtJ8SPBFwAkRuiHKpA6sRN/Lu7zG5i14kctaUqRGhGXnu9O/Pt7MzsMiklvF+9t2kWTDvyIrAsA0aKRRi1T0C/hJ4LUbt5/8rNpWVlp8RSr9J40b48fxFaTQ9+ft8EZ6MJYb0Ok+dnYGpmPgXwKIAvLx8vYXc5GdMAQJgQEkpjRTh36TS2U+DWW/D17WuYgm8pwJyY1npZsZKOxImOV1I/h4+O6vEg5GCZBpgmA6hX8wHKUHDRBXQYicQ4rlc3Tf0VMs8DHBS864F2YFspjgUYjKX/Az3gsdQd2eeBHwmdGWXHcgBGSkZXOXohcEXebRoQcAgjqediNY+AVyu3Z3sAKqfKoGMsewBeEIOPgQxxPJIjcGH6qtL/0AdADzKGnuuD+2tLK7Q8DhHHbOBW+KEzcHLuYc82MkEUekLiwuvVH+guQBQzOG4XdAb8EOcRcqQvDkY2iCLuxECJ43JobMXoutqGgDa2T7UqLKwt9KRyuxKVByqVXXqIoCCUCAqhUOioTWC7G4TQEOD0APy2/7G2Xpu1J4+lxeQ4TXBbITDpoVelRN/BVFbwu5oMMJUBhoXy5tmdRcMwymP2OLQaLjx9/vnBo6V3K6izATmSnMa0Dq7ferIohJhr1p01zrlz49rZF4OMs8JkX23vVQzYp+wbYGV/KpXKjvspl8tsIKCrMNAYFxj2GKS5ZWxg4ewKsJfaGMIY5KXqPz8LBBj6+yDvVP79+yDp/9F9oIx3OisHWwe7Oal0HxCAAAQgAAEIQAACEIAABCAAAQhAAAIQgAAEIAABCEAAAhCAAAQgwD8E/BZgAP0qhKj3rXO7AAAAAElFTkSuQmCC") no-repeat;
}
.css-treeview label, .css-treeview span, .css-treeview label::before {
display: inline-block;
height: 16px;
line-height: 16px;
vertical-align: middle;
}
.css-treeview label {
background-position: 18px 0;
}
.css-treeview label::before {
content: "";
width: 16px;
margin: 0 22px 0 0;
vertical-align: middle;
background-position: 0 -32px;
}
.css-treeview input:checked + label::before {
background-position: 0 -16px;
}
/* webkit adjacent element selector bugfix */
@media screen and (-webkit-min-device-pixel-ratio:0)
{
.css-treeview{
-webkit-animation: webkit-adjacent-element-selector-bugfix infinite 1s;
}
@-webkit-keyframes webkit-adjacent-element-selector-bugfix
{
from {
padding: 0;
}
to {
padding: 0;
}
}
}
#uploader {
position: absolute;
top: 0;
right: 0;
left: 0;
height:28px;
line-height: 24px;
padding-left: 10px;
background-color: #444;
color:#EEE;
}
#tree {
position: absolute;
top: 28px;
bottom: 0;
left: 0;
width:200px;
padding: 8px;
}
#editor, #preview {
position: absolute;
top: 28px;
right: 0;
bottom: 0;
left: 200px;
}
#preview {
background-color: #EEE;
padding:5px;
}
</style>
<script>
function createFileUploader(element, tree, editor){
var xmlHttp;
var input = document.createElement("input");
input.type = "file";
input.multiple = false;
input.name = "data";
document.getElementById(element).appendChild(input);
var path = document.createElement("input");
path.id = "upload-path";
path.type = "text";
path.name = "path";
path.defaultValue = "/";
document.getElementById(element).appendChild(path);
var button = document.createElement("button");
button.innerHTML = 'Upload';
document.getElementById(element).appendChild(button);
var mkdir = document.createElement("button");
mkdir.innerHTML = 'MkDir';
document.getElementById(element).appendChild(mkdir);
var mkfile = document.createElement("button");
mkfile.innerHTML = 'MkFile';
document.getElementById(element).appendChild(mkfile);
function httpPostProcessRequest(){
if (xmlHttp.readyState == 4){
if(xmlHttp.status != 200) alert("ERROR["+xmlHttp.status+"]: "+xmlHttp.responseText);
else {
tree.refreshPath(path.value);
}
}
}
function createPath(p){
xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = httpPostProcessRequest;
var formData = new FormData();
formData.append("path", p);
xmlHttp.open("PUT", "/edit");
xmlHttp.send(formData);
}
mkfile.onclick = function(e){
if(path.value.indexOf(".") === -1) return;
createPath(path.value);
editor.loadUrl(path.value);
};
mkdir.onclick = function(e){
if(path.value.length < 2) return;
var dir = path.value
if(dir.indexOf(".") !== -1){
if(dir.lastIndexOf("/") === 0) return;
dir = dir.substring(0, dir.lastIndexOf("/"));
}
createPath(dir);
};
button.onclick = function(e){
if(input.files.length === 0){
return;
}
xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = httpPostProcessRequest;
var formData = new FormData();
formData.append("data", input.files[0], path.value);
xmlHttp.open("POST", "/edit");
xmlHttp.send(formData);
}
input.onchange = function(e){
if(input.files.length === 0) return;
var filename = input.files[0].name;
var ext = /(?:\.([^.]+))?$/.exec(filename)[1];
var name = /(.*)\.[^.]+$/.exec(filename)[1];
if(typeof name !== undefined){
if(name.length > 8) name = name.substring(0, 8);
filename = name;
}
if(typeof ext !== undefined){
if(ext === "html") ext = "htm";
else if(ext === "jpeg") ext = "jpg";
filename = filename + "." + ext;
}
if(path.value === "/" || path.value.lastIndexOf("/") === 0){
path.value = "/"+filename;
} else {
path.value = path.value.substring(0, path.value.lastIndexOf("/")+1)+filename;
}
}
}
function createTree(element, editor){
var preview = document.getElementById("preview");
var treeRoot = document.createElement("div");
treeRoot.className = "css-treeview";
document.getElementById(element).appendChild(treeRoot);
function loadDownload(path){
document.getElementById('download-frame').src = path+"?download=true";
}
function loadPreview(path){
document.getElementById("editor").style.display = "none";
preview.style.display = "block";
preview.innerHTML = '<img src="'+path+'" style="max-width:100%; max-height:100%; margin:auto; display:block;" />';
}
function fillFolderMenu(el, path){
var list = document.createElement("ul");
el.appendChild(list);
var action = document.createElement("li");
list.appendChild(action);
var isChecked = document.getElementById(path).checked;
var expnd = document.createElement("li");
list.appendChild(expnd);
if(isChecked){
expnd.innerHTML = "<span>Collapse</span>";
expnd.onclick = function(e){
document.getElementById(path).checked = false;
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
};
var refrsh = document.createElement("li");
list.appendChild(refrsh);
refrsh.innerHTML = "<span>Refresh</span>";
refrsh.onclick = function(e){
var leaf = document.getElementById(path).parentNode;
if(leaf.childNodes.length == 3) leaf.removeChild(leaf.childNodes[2]);
httpGet(leaf, path);
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
};
} else {
expnd.innerHTML = "<span>Expand</span>";
expnd.onclick = function(e){
document.getElementById(path).checked = true;
var leaf = document.getElementById(path).parentNode;
if(leaf.childNodes.length == 3) leaf.removeChild(leaf.childNodes[2]);
httpGet(leaf, path);
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
};
}
var upload = document.createElement("li");
list.appendChild(upload);
upload.innerHTML = "<span>Upload</span>";
upload.onclick = function(e){
var pathEl = document.getElementById("upload-path");
if(pathEl){
var subPath = pathEl.value;
if(subPath.lastIndexOf("/") < 1) pathEl.value = path+subPath;
else pathEl.value = path.substring(subPath.lastIndexOf("/"))+subPath;
}
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
};
var delFile = document.createElement("li");
list.appendChild(delFile);
delFile.innerHTML = "<span>Delete</span>";
delFile.onclick = function(e){
httpDelete(path);
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
};
}
function fillFileMenu(el, path){
var list = document.createElement("ul");
el.appendChild(list);
var action = document.createElement("li");
list.appendChild(action);
if(isTextFile(path)){
action.innerHTML = "<span>Edit</span>";
action.onclick = function(e){
editor.loadUrl(path);
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
};
} else if(isImageFile(path)){
action.innerHTML = "<span>Preview</span>";
action.onclick = function(e){
loadPreview(path);
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
};
}
var download = document.createElement("li");
list.appendChild(download);
download.innerHTML = "<span>Download</span>";
download.onclick = function(e){
loadDownload(path);
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
};
var delFile = document.createElement("li");
list.appendChild(delFile);
delFile.innerHTML = "<span>Delete</span>";
delFile.onclick = function(e){
httpDelete(path);
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(el);
};
}
function showContextMenu(e, path, isfile){
var divContext = document.createElement("div");
var scrollTop = document.body.scrollTop ? document.body.scrollTop : document.documentElement.scrollTop;
var scrollLeft = document.body.scrollLeft ? document.body.scrollLeft : document.documentElement.scrollLeft;
var left = e.clientX + scrollLeft;
var top = e.clientY + scrollTop;
divContext.className = 'contextMenu';
divContext.style.display = 'block';
divContext.style.left = left + 'px';
divContext.style.top = top + 'px';
if(isfile) fillFileMenu(divContext, path);
else fillFolderMenu(divContext, path);
document.body.appendChild(divContext);
var width = divContext.offsetWidth;
var height = divContext.offsetHeight;
divContext.onmouseout = function(e){
if(e.clientX < left || e.clientX > (left + width) || e.clientY < top || e.clientY > (top + height)){
if(document.body.getElementsByClassName('contextMenu').length > 0) document.body.removeChild(divContext);
}
};
}
function createTreeLeaf(path, name, size){
var leaf = document.createElement("li");
leaf.id = (((path == "/")?"":path)+"/"+name).toLowerCase();
var label = document.createElement("span");
label.textContent = name.toLowerCase();
leaf.appendChild(label);
leaf.onclick = function(e){
if(isTextFile(leaf.id)){
editor.loadUrl(leaf.id);
} else if(isImageFile(leaf.id)){
loadPreview(leaf.id);
}
};
leaf.oncontextmenu = function(e){
e.preventDefault();
e.stopPropagation();
showContextMenu(e, leaf.id, true);
};
return leaf;
}
function createTreeBranch(path, name, disabled){
var leaf = document.createElement("li");
var check = document.createElement("input");
check.type = "checkbox";
check.id = (((path == "/")?"":path)+"/"+name).toLowerCase();
if(typeof disabled !== "undefined" && disabled) check.disabled = "disabled";
leaf.appendChild(check);
var label = document.createElement("label");
label.for = check.id;
label.textContent = name.toLowerCase();
leaf.appendChild(label);
check.onchange = function(e){
if(check.checked){
if(leaf.childNodes.length == 3) leaf.removeChild(leaf.childNodes[2]);
httpGet(leaf, check.id);
}
};
label.onclick = function(e){
if(!check.checked){
check.checked = true;
if(leaf.childNodes.length == 3) leaf.removeChild(leaf.childNodes[2]);
httpGet(leaf, check.id);
} else {
check.checked = false;
}
};
leaf.oncontextmenu = function(e){
e.preventDefault();
e.stopPropagation();
showContextMenu(e, check.id, false);
}
return leaf;
}
function addList(parent, path, items){
var list = document.createElement("ul");
parent.appendChild(list);
var ll = items.length;
for(var i = 0; i < ll; i++){
var item = items[i];
var itemEl;
if(item.type === "file"){
itemEl = createTreeLeaf(path, item.name, item.size);
} else {
itemEl = createTreeBranch(path, item.name);
}
list.appendChild(itemEl);
}
}
function isTextFile(path){
var ext = /(?:\.([^.]+))?$/.exec(path)[1];
if(typeof ext !== undefined){
switch(ext){
case "txt":
case "htm":
case "html":
case "js":
case "json":
case "c":
case "h":
case "cpp":
case "css":
case "xml":
return true;
}
}
return false;
}
function isImageFile(path){
var ext = /(?:\.([^.]+))?$/.exec(path)[1];
if(typeof ext !== undefined){
switch(ext){
case "png":
case "jpg":
case "gif":
case "ico":
return true;
}
}
return false;
}
this.refreshPath = function(path){
if(path.lastIndexOf('/') < 1){
path = '/';
treeRoot.removeChild(treeRoot.childNodes[0]);
httpGet(treeRoot, "/");
} else {
path = path.substring(0, path.lastIndexOf('/'));
var leaf = document.getElementById(path).parentNode;
if(leaf.childNodes.length == 3) leaf.removeChild(leaf.childNodes[2]);
httpGet(leaf, path);
}
};
function delCb(path){
return function(){
if (xmlHttp.readyState == 4){
if(xmlHttp.status != 200){
alert("ERROR["+xmlHttp.status+"]: "+xmlHttp.responseText);
} else {
if(path.lastIndexOf('/') < 1){
path = '/';
treeRoot.removeChild(treeRoot.childNodes[0]);
httpGet(treeRoot, "/");
} else {
path = path.substring(0, path.lastIndexOf('/'));
var leaf = document.getElementById(path).parentNode;
if(leaf.childNodes.length == 3) leaf.removeChild(leaf.childNodes[2]);
httpGet(leaf, path);
}
}
}
}
}
function httpDelete(filename){
xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = delCb(filename);
var formData = new FormData();
formData.append("path", filename);
xmlHttp.open("DELETE", "/edit");
xmlHttp.send(formData);
}
function getCb(parent, path){
return function(){
if (xmlHttp.readyState == 4){
//clear loading
if(xmlHttp.status == 200) addList(parent, path, JSON.parse(xmlHttp.responseText));
}
}
}
function httpGet(parent, path){
xmlHttp = new XMLHttpRequest(parent, path);
xmlHttp.onreadystatechange = getCb(parent, path);
xmlHttp.open("GET", "/list?dir="+path, true);
xmlHttp.send(null);
//start loading
}
httpGet(treeRoot, "/");
return this;
}
function createEditor(element, file, lang, theme, type){
function getLangFromFilename(filename){
var lang = "plain";
var ext = /(?:\.([^.]+))?$/.exec(filename)[1];
if(typeof ext !== undefined){
switch(ext){
case "txt": lang = "plain"; break;
case "htm": lang = "html"; break;
case "js": lang = "javascript"; break;
case "c": lang = "c_cpp"; break;
case "cpp": lang = "c_cpp"; break;
case "css":
case "scss":
case "php":
case "html":
case "json":
case "xml":
lang = ext;
}
}
return lang;
}
if(typeof file === "undefined") file = "/index.htm";
if(typeof lang === "undefined"){
lang = getLangFromFilename(file);
}
if(typeof theme === "undefined") theme = "textmate";
if(typeof type === "undefined"){
type = "text/"+lang;
if(lang === "c_cpp") type = "text/plain";
}
var xmlHttp = null;
var editor = ace.edit(element);
//post
function httpPostProcessRequest(){
if (xmlHttp.readyState == 4){
if(xmlHttp.status != 200) alert("ERROR["+xmlHttp.status+"]: "+xmlHttp.responseText);
}
}
function httpPost(filename, data, type){
xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = httpPostProcessRequest;
var formData = new FormData();
formData.append("data", new Blob([data], { type: type }), filename);
xmlHttp.open("POST", "/edit");
xmlHttp.send(formData);
}
//get
function httpGetProcessRequest(){
if (xmlHttp.readyState == 4){
document.getElementById("preview").style.display = "none";
document.getElementById("editor").style.display = "block";
if(xmlHttp.status == 200) editor.setValue(xmlHttp.responseText);
else editor.setValue("");
editor.clearSelection();
}
}
function httpGet(theUrl){
xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = httpGetProcessRequest;
xmlHttp.open("GET", theUrl, true);
xmlHttp.send(null);
}
if(lang !== "plain") editor.getSession().setMode("ace/mode/"+lang);
editor.setTheme("ace/theme/"+theme);
editor.$blockScrolling = Infinity;
editor.getSession().setUseSoftTabs(true);
editor.getSession().setTabSize(2);
editor.setHighlightActiveLine(true);
editor.setShowPrintMargin(false);
editor.commands.addCommand({
name: 'saveCommand',
bindKey: {win: 'Ctrl-S', mac: 'Command-S'},
exec: function(editor) {
httpPost(file, editor.getValue()+"", type);
},
readOnly: false
});
editor.commands.addCommand({
name: 'undoCommand',
bindKey: {win: 'Ctrl-Z', mac: 'Command-Z'},
exec: function(editor) {
editor.getSession().getUndoManager().undo(false);
},
readOnly: false
});
editor.commands.addCommand({
name: 'redoCommand',
bindKey: {win: 'Ctrl-Shift-Z', mac: 'Command-Shift-Z'},
exec: function(editor) {
editor.getSession().getUndoManager().redo(false);
},
readOnly: false
});
httpGet(file);
editor.loadUrl = function(filename){
file = filename;
lang = getLangFromFilename(file);
type = "text/"+lang;
if(lang !== "plain") editor.getSession().setMode("ace/mode/"+lang);
httpGet(file);
}
return editor;
}
function onBodyLoad(){
var vars = {};
var parts = window.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m,key,value) { vars[key] = value; });
var editor = createEditor("editor", vars.file, vars.lang, vars.theme);
var tree = createTree("tree", editor);
createFileUploader("uploader", tree, editor);
};
</script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.1.9/ace.js" type="text/javascript" charset="utf-8"></script>
</head>
<body onload="onBodyLoad();">
<div id="uploader"></div>
<div id="tree"></div>
<div id="editor"></div>
<div id="preview" style="display:none;"></div>
<iframe id=download-frame style='display:none;'></iframe>
</body>
</html>
Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

File diff suppressed because one or more lines are too long
Binary file not shown.
-4
View File
@@ -1,4 +0,0 @@
## Retired, use:
McLightingHTML from https://github.com/FabLab-Luenen/McLightingHTML
or set #define USE_HTML_MIN_GZ in definitions.h to use the integrated!
-491
View File
@@ -1,491 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<!--Import Google Icon Font-->
<link href="http://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<!--Import materialize.css-->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/css/materialize.min.css" media="screen,projection" />
<!--Let browser know website is optimized for mobile-->
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
<meta name="mobile-web-app-capable" content="yes">
<meta charset="utf-8"/>
<meta name="mobile-web-app-capable" content="yes">
<title>McLighting (RGBW) v2</title>
</head>
<body>
<nav class="blue light-blueXXX lighten-1XXX" role="navigation" id="mc-nav">
<div class="nav-wrapper container">
<a id="logo-container" href="#" class="brand-logo">McLighting (RGBW) v2</a>
<ul class="right hide-on-med-and-down">
<li><a href="#" class="mc-navlink" data-pane="pane1">Wheel</a></li>
<li><a href="#" class="mc-navlink" data-pane="pane2">Modes</a></li>
</ul>
<ul id="nav-mobile" class="side-nav">
<li><a href="#" class="mc-navlink" data-pane="pane1">Wheel</a></li>
<li><a href="#" class="mc-navlink" data-pane="pane2">Modes</a></li>
</ul>
<a href="#" data-activates="nav-mobile" class="button-collapse"><i class="material-icons">menu</i></a>
</div>
</nav>
<div class="container mc_pane" id="pane0">
<div class="section">
<div class="row" id="mc-wsloader">
<div class="col">
<div class="preloader-wrapper active">
<div class="spinner-layer spinner-blue-only">
<div class="circle-clipper left">
<div class="circle"></div>
</div>
<div class="gap-patch">
<div class="circle"></div>
</div>
<div class="circle-clipper right">
<div class="circle"></div>
</div>
</div>
</div>
</div>
</div>
<div class="row hide" id="mc-wserror">
<div class="col">
<div>Error on websocket connect.</div>
</div>
</div>
</div>
</div>
<div class="container mc_pane hide" id="pane1">
<div class="section">
<div class="row">
<div class="col s12 m6">
<div style="height: 330px; width: 330px;">
<canvas id="myCanvas" width="330" height="330" style="-webkit-user-select: none;-webkit-tap-highlight-color: rgba(0,0,0,0);-moz-user-select:none;"></canvas>
</div>
</div>
<div class="col s12 m6">
<div class="card-panel" id="status">
<div id="status_pos">pick a color</div>
<div id="status_color"></div>
</div>
</div>
<div class="col s12 m6">
<div class="right switch">Auto:<br>
<label>Off
<input id="autoSwitch" type="checkbox"><span class="lever"></span>On
</label>
</div>
</div>
</div>
</div>
</div>
<div class="container mc_pane hide" id="pane2">
<div class="section">
<div class="row">
<form class="col s12">
<div class="row">
<div class="input-field col s12 l4">
<label for="txt_red">Red</label><br/>
<p class="range-field"><input type="range" id="rng_red" min="0" max="255" class="update_colors" /></p>
</div>
<div class="input-field col s12 l4">
<label for="txt_green">Green</label><br/>
<p class="range-field"><input type="range" id="rng_green" min="0" max="255" class="update_colors" /></p>
</div>
<div class="input-field col s12 l4">
<label for="txt_blue">Blue</label><br/>
<p class="range-field"><input type="range" id="rng_blue" min="0" max="255" class="update_colors" /></p>
</div>
</div>
<div class="row">
<div class="input-field col s12">
<label for="txt_white">White</label><br/>
<p class="range-field"><input type="range" id="rng_white" min="0" max="255" class="update_colors" /></p>
</div>
</div>
<div class="row">
<div class="input-field col s12">
<label for="txt_delay">Speed</label><br/>
<p class="range-field"><input type="range" id="rng_delay" min="0" max="255" value="196" class="update_delay" /></p>
</div>
</div>
<div class="row">
<div class="input-field col s12">
<label for="txt_delay">Brightness</label><br/>
<p class="range-field"><input type="range" id="rng_brightness" min="0" max="255" value="196" class="update_brightness" /></p>
</div>
</div>
</form>
</div>
<div class="row">
<div id="modes">
<div class="input-field col s12">
Loading animations...
</div>
</div>
</div>
</div>
</div>
<footer class="page-footer blue">
<div class="footer-copyright">
<div class="container">© 2017
<a class="grey-text text-lighten-4 right" href="https://github.com/toblum/McLighting">Project home</a>
</div>
</div>
</footer>
<style type="text/css">
.btn_grid {
margin: 7px 0;
}
</style>
<!--Import jQuery before materialize.js-->
<script type="text/javascript" src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/js/materialize.min.js"></script>
<script type="text/javascript">(function($){
$(function(){
// Settings
var host = window.location.hostname;
//host = "esp8266_02.local";
var ws_url = 'ws://' + host + ':81';
var connection;
var ws_waiting = 0;
// ******************************************************************
// Side navigation
// ******************************************************************
$('.button-collapse').sideNav();
// Navlinks
$('#mc-nav').on('click', '.mc-navlink', function(){
console.log("Navigate to pane: ", $(this).data("pane"));
showPane($(this).data("pane"));
});
function showPane(pane) {
$('.mc_pane').addClass('hide');
$('#' + pane).removeClass('hide');
$('.button-collapse').sideNav('hide');
//if (pane == "pane2") {
// setMainColor();
//}
}
// ******************************************************************
// init()
// ******************************************************************
function init() {
console.log("Connection websockets to:", ws_url);
connection = new WebSocket(ws_url, ['arduino']);
var mode = 0;
var ws2812fx_mode = 0;
$.getJSON("http://" + host + "/status", function(data) {
console.log("status", data);
mode = data.mode;
if (mode == "1") {
// set autoswitch $("#autoSwitch").val('checked');
}
ws2812fx_mode = data.ws2812fx_mode;
$("#rng_delay").val(data.speed);
$("#rng_brightness").val(data.brightness);
$("#rng_white").val(data.color[0]);
$("#rng_red").val(data.color[1]);
$("#rng_green").val(data.color[2]);
$("#rng_blue").val(data.color[3]);
var statusColor = "#" + componentToHex(data.color[1]) + componentToHex(data.color[2]) + componentToHex(data.color[3]);
$('#status').css("backgroundColor", statusColor);
$('#status_color').text(statusColor + "- R=" + data.color[1] + ", G=" + data.color[2] + ", B=" + data.color[3]);
});
// Load modes async
// List of all color modes
// enum MODE {OFF, AUTO, TV, E131, SET_MODE, HOLD, CUSTOM, SETCOLOR, SETSPEED, BRIGHTNESS, WIPE, RAINBOW, RAINBOWCYCLE, THEATERCHASE, TWINKLERANDOM, THEATERCHASERAINBOW};
$.getJSON("http://" + host + "/get_modes", function(data) {
console.log("modes", data);
var modes_html = "";
data.forEach(function(current_mode){
if (current_mode.mode !== undefined) {
modes_html += '<div class="col s12 m6 l6 btn_grid">';
if ((mode == "5" && current_mode.mode == ws2812fx_mode) || (mode == "0" && current_mode.mode == "off") || (mode == "2" && current_mode.mode == "tv") || (mode == "3" && current_mode.mode == "e131")){
modes_html += '<a class="btn waves-effect waves-light btn_mode red" name="action" data-mode="' + current_mode.mode + '">(' + current_mode.mode +') '+ current_mode.name;
} else {
modes_html += '<a class="btn waves-effect waves-light btn_mode blue" name="action" data-mode="' + current_mode.mode + '">(' + current_mode.mode +') '+ current_mode.name;
}
modes_html += '<i class="material-icons right">send</i>';
modes_html += '</a>';
modes_html += '</div>';
}
});
$('#modes').html(modes_html);
});
// When the connection is open, send some data to the server
connection.onopen = function () {
//connection.send('Ping'); // Send the message 'Ping' to the server
console.log('WebSocket Open');
showPane('pane1');
};
// Log errors
connection.onerror = function (error) {
console.log('WebSocket Error ' + error);
$('#mc-wsloader').addClass('hide');
$('#mc-wserror').removeClass('hide');
};
// Log messages from the server
connection.onmessage = function (e) {
console.log('WebSocket from server: ' + e.data);
ws_waiting = 0;
};
}
// ******************************************************************
// Modes
// ******************************************************************
$("#pane2").on("click", ".btn_mode", function() {
var mode = $(this).attr("data-mode");
last_mode = mode;
var btn = $(this);
setMode(mode, function() {
$(".btn_mode, .btn_mode_static").removeClass("red").addClass("blue");
btn.removeClass("blue").addClass("red");
});
});
$("#pane2").on("click", ".btn_mode_static", function() {
var mode = $(this).attr("data-mode");
var btn = $(this);
wsSendCommand("=" + mode);
$(".btn_mode, .btn_mode_static").removeClass("red").addClass("blue");
btn.removeClass("blue").addClass("red");
});
$("#pane2").on("change", ".update_colors", setMainColor);
$("#pane2").on("change", ".update_delay", function() {
var delay = $("#rng_delay").val();
wsSendCommand("?" + delay);
});
$("#pane2").on("change", ".update_brightness", function() {
var brightness = $("#rng_brightness").val();
wsSendCommand("%" + brightness);
});
$("#autoSwitch").on("change", function () {
if ($(this).prop('checked')) {
wsSendCommand("start");
} else {
wsSendCommand("stop");
}
});
function setMode(mode, finish_funtion) {
console.log("Mode: ", mode);
wsSendCommand("/" + mode);
finish_funtion();
}
function setMainColor() {
var white = $("#rng_white").val();
var red = $("#rng_red").val();
var green = $("#rng_green").val();
var blue = $("#rng_blue").val();
var hexColor = componentToHex(white) + componentToHex(red) + componentToHex(green) + componentToHex(blue);
var statusColor = "#" + componentToHex(red) + componentToHex(green) + componentToHex(blue);
wsSetMainColor(hexColor);
$('#status').css("backgroundColor", statusColor);
$('#status_color').text(statusColor + "- R=" + red + ", G=" + green + ", B=" + blue);
}
// ******************************************************************
// WebSocket commands
// ******************************************************************
function wsSendCommand(cmd) {
console.log("Send WebSocket command:", cmd);
if (ws_waiting == 0) {
connection.send(cmd);
ws_waiting++;
} else {
console.log("++++++++ WS call waiting, skip")
}
}
function wsSetAll(hexColor) {
console.log("wsSetAll() Set all colors to:", hexColor);
wsSendCommand("*" + hexColor);
}
function wsSetMainColor(hexColor) {
console.log("wsSetMainColor() Set main colors to:", hexColor);
wsSendCommand("#" + hexColor);
}
// ******************************************************************
// Colorwheel
// ******************************************************************
// this is supposed to work on mobiles (touch) as well as on a desktop (click)
// since we couldn't find a decent one .. this try of writing one by myself
// + google. swiping would be really nice - I will possibly implement it with
// jquery later - or never.
var canvas = document.getElementById("myCanvas");
// FIX: Cancel touch end event and handle click via touchstart
// canvas.addEventListener("touchend", function(e) { e.preventDefault(); }, false);
canvas.addEventListener("touchmove", doTouch, false);
canvas.addEventListener("click", doClick, false);
//canvas.addEventListener("mousemove", doClick, false);
var context = canvas.getContext('2d');
var centerX = canvas.width / 2;
var centerY = canvas.height / 2;
var innerRadius = canvas.width / 4.5;
var outerRadius = (canvas.width - 10) / 2
//outer border
context.beginPath();
//outer circle
context.arc(centerX, centerY, outerRadius, 0, 2 * Math.PI, false);
//draw the outer border: (gets drawn around the circle!)
context.lineWidth = 4;
context.strokeStyle = '#000000';
context.stroke();
context.closePath();
//fill with beautiful colors
//taken from here: http://stackoverflow.com/questions/18265804/building-a-color-wheel-in-html5
for(var angle=0; angle<=360; angle+=1) {
var startAngle = (angle-2)*Math.PI/180;
var endAngle = angle * Math.PI/180;
context.beginPath();
context.moveTo(centerX, centerY);
context.arc(centerX, centerY, outerRadius, startAngle, endAngle, false);
context.closePath();
context.fillStyle = 'hsl('+angle+', 100%, 50%)';
context.fill();
context.closePath();
}
//inner border
context.beginPath();
//context.arc(centerX, centerY, radius, startAngle, endAngle, counterClockwise);
context.arc(centerX, centerY, innerRadius, 0, 2 * Math.PI, false);
//fill the center
var my_gradient=context.createLinearGradient(0,0,170,0);
my_gradient.addColorStop(0,"black");
my_gradient.addColorStop(1,"white");
context.fillStyle = my_gradient;
context.fillStyle = "white";
context.fill();
//draw the inner line
context.lineWidth = 2;
context.strokeStyle = '#000000';
context.stroke();
context.closePath();
//get Mouse x/y canvas position
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
//comp to Hex
function componentToHex(c) {
//var hex = c.toString(16);
//return hex.length == 1 ? "0" + hex : hex;
return ("0"+(Number(c).toString(16))).slice(-2).toUpperCase();
}
//rgb/rgba to Hex
function rgbToHex(rgb) {
return componentToHex(rgb[0]) + componentToHex(rgb[1]) + componentToHex(rgb[2]);
}
//display the touch/click position and color info
function updateStatus(pos, color) {
//var hexColor = rgbToHex(color);
//wsSetAll(hexColor);
var hexColor = componentToHex(color[0]) + componentToHex(color[1]) + componentToHex(color[2]);
wsSetMainColor(hexColor);
hexColor = "#" + hexColor;
$('#status').css("backgroundColor", hexColor);
$('#status_color').text(hexColor + " - R=" + color[0] + ", G=" + color[1] + ", B=" + color[2]);
$('#status_pos').text("x: " + pos.x + " - y: " + pos.y);
$("#rng_white").val(0);
$("#rng_red").val(color[0]);
$("#rng_green").val(color[1]);
$("#rng_blue").val(color[2]);
}
//handle the touch event
function doTouch(event) {
//to not also fire on click
event.preventDefault();
var el = event.target;
//touch position
var pos = {x: Math.round(event.targetTouches[0].pageX - el.offsetLeft),
y: Math.round(event.targetTouches[0].pageY - el.offsetTop)};
//color
var color = context.getImageData(pos.x, pos.y, 1, 1).data;
updateStatus(pos, color);
}
function doClick(event) {
//click position
var pos = getMousePos(canvas, event);
//color
var color = context.getImageData(pos.x, pos.y, 1, 1).data;
//console.log("click", pos.x, pos.y, color);
updateStatus(pos, color);
//now do sth with the color rgbToHex(color);
//don't do stuff when #000000 (outside circle and lines
}
// ******************************************************************
// main
// ******************************************************************
init();
}); // end of document ready
})(jQuery); // end of jQuery name space</script>
</body>
</html>
-55
View File
@@ -1,55 +0,0 @@
var gulp = require('gulp'),
request = require('request'),
fs = require('fs'),
connect = require('gulp-connect'),
fileinclude = require('gulp-file-include');
var src_dir = "src/";
var build_dir = "build/";
gulp.task('html', function() {
gulp.src(src_dir + '*.htm')
.pipe(fileinclude({
prefix: '@@',
basepath: '@file'
}))
.pipe(gulp.dest('build'))
.pipe(connect.reload());
});
gulp.task('connect', function() {
connect.server({
root: 'build',
livereload: true
});
});
gulp.task('watch', function() {
gulp.watch(src_dir + '*.htm', ['html']);
gulp.watch(src_dir + 'js/*.js', ['html']);
});
gulp.task('upload', ['html'], function() {
var url = 'http://192.168.0.49/edit';
var options = {
url: url,
headers: {
'Content-Type': 'multipart/form-data'
}
};
var r = request.post(options, function optionalCallback(err, httpResponse, body) {
if (err) {
return console.error('upload failed:', err);
}
console.log('Upload successful! Server responded with:', body);
});
var form = r.form();
form.append('data', fs.createReadStream(__dirname + "/" + build_dir + '/index.htm'), {filename: '/index.htm', contentType: "application/octet-stream"});
});
gulp.task('default', ['html']);
gulp.task('serve', ['watch', 'connect']);
-18
View File
@@ -1,18 +0,0 @@
{
"name": "mc_lighting",
"version": "2.0.0",
"description": "Web client for Mc Lighting",
"main": "index.html",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Tobias Blum",
"license": "MIT",
"dependencies": {
"fs": "0.0.2",
"gulp": "^3.9.1",
"gulp-connect": "^5.0.0",
"gulp-file-include": "^1.0.0",
"request": "^2.72.0"
}
}
-159
View File
@@ -1,159 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<!--Import Google Icon Font-->
<link href="http://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<!--Import materialize.css-->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/css/materialize.min.css" media="screen,projection" />
<!--Let browser know website is optimized for mobile-->
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
<meta name="mobile-web-app-capable" content="yes">
<meta charset="utf-8"/>
<meta name="mobile-web-app-capable" content="yes">
<title>McLighting (RGBW) v2</title>
</head>
<body>
<nav class="blue light-blueXXX lighten-1XXX" role="navigation" id="mc-nav">
<div class="nav-wrapper container">
<a id="logo-container" href="#" class="brand-logo">McLighting (RGBW) v2</a>
<ul class="right hide-on-med-and-down">
<li><a href="#" class="mc-navlink" data-pane="pane1">Wheel</a></li>
<li><a href="#" class="mc-navlink" data-pane="pane2">Modes</a></li>
</ul>
<ul id="nav-mobile" class="side-nav">
<li><a href="#" class="mc-navlink" data-pane="pane1">Wheel</a></li>
<li><a href="#" class="mc-navlink" data-pane="pane2">Modes</a></li>
</ul>
<a href="#" data-activates="nav-mobile" class="button-collapse"><i class="material-icons">menu</i></a>
</div>
</nav>
<div class="container mc_pane" id="pane0">
<div class="section">
<div class="row" id="mc-wsloader">
<div class="col">
<div class="preloader-wrapper active">
<div class="spinner-layer spinner-blue-only">
<div class="circle-clipper left">
<div class="circle"></div>
</div>
<div class="gap-patch">
<div class="circle"></div>
</div>
<div class="circle-clipper right">
<div class="circle"></div>
</div>
</div>
</div>
</div>
</div>
<div class="row hide" id="mc-wserror">
<div class="col">
<div>Error on websocket connect.</div>
</div>
</div>
</div>
</div>
<div class="container mc_pane hide" id="pane1">
<div class="section">
<div class="row">
<div class="col s12 m6">
<div style="height: 330px; width: 330px;">
<canvas id="myCanvas" width="330" height="330" style="-webkit-user-select: none;-webkit-tap-highlight-color: rgba(0,0,0,0);-moz-user-select:none;"></canvas>
</div>
</div>
<div class="col s12 m6">
<div class="card-panel" id="status">
<div id="status_pos">pick a color</div>
<div id="status_color"></div>
</div>
</div>
<div class="col s12 m6">
<div class="right switch">Auto:<br>
<label>Off
<input id="autoSwitch" type="checkbox"><span class="lever"></span>On
</label>
</div>
</div>
</div>
</div>
</div>
<div class="container mc_pane hide" id="pane2">
<div class="section">
<div class="row">
<form class="col s12">
<div class="row">
<div class="input-field col s12 l4">
<label for="txt_red">Red</label><br/>
<p class="range-field"><input type="range" id="rng_red" min="0" max="255" class="update_colors" /></p>
</div>
<div class="input-field col s12 l4">
<label for="txt_green">Green</label><br/>
<p class="range-field"><input type="range" id="rng_green" min="0" max="255" class="update_colors" /></p>
</div>
<div class="input-field col s12 l4">
<label for="txt_blue">Blue</label><br/>
<p class="range-field"><input type="range" id="rng_blue" min="0" max="255" class="update_colors" /></p>
</div>
</div>
<div class="row">
<div class="input-field col s12">
<label for="txt_white">White</label><br/>
<p class="range-field"><input type="range" id="rng_white" min="0" max="255" class="update_colors" /></p>
</div>
</div>
<div class="row">
<div class="input-field col s12">
<label for="txt_delay">Speed</label><br/>
<p class="range-field"><input type="range" id="rng_delay" min="0" max="255" value="196" class="update_delay" /></p>
</div>
</div>
<div class="row">
<div class="input-field col s12">
<label for="txt_delay">Brightness</label><br/>
<p class="range-field"><input type="range" id="rng_brightness" min="0" max="255" value="196" class="update_brightness" /></p>
</div>
</div>
</form>
</div>
<div class="row">
<div id="modes">
<div class="input-field col s12">
Loading animations...
</div>
</div>
</div>
</div>
</div>
<footer class="page-footer blue">
<div class="footer-copyright">
<div class="container">© 2017
<a class="grey-text text-lighten-4 right" href="https://github.com/toblum/McLighting">Project home</a>
</div>
</div>
</footer>
<style type="text/css">
.btn_grid {
margin: 7px 0;
}
</style>
<!--Import jQuery before materialize.js-->
<script type="text/javascript" src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/js/materialize.min.js"></script>
<script type="text/javascript">@@include('js/script.js')</script>
</body>
\ No newline at end of file
</html>
-331
View File
@@ -1,331 +0,0 @@
(function($){
$(function(){
// Settings
var host = window.location.hostname;
//host = "esp8266_02.local";
var ws_url = 'ws://' + host + ':81';
var connection;
var ws_waiting = 0;
// ******************************************************************
// Side navigation
// ******************************************************************
$('.button-collapse').sideNav();
// Navlinks
$('#mc-nav').on('click', '.mc-navlink', function(){
console.log("Navigate to pane: ", $(this).data("pane"));
showPane($(this).data("pane"));
});
function showPane(pane) {
$('.mc_pane').addClass('hide');
$('#' + pane).removeClass('hide');
$('.button-collapse').sideNav('hide');
//if (pane == "pane2") {
// setMainColor();
//}
}
// ******************************************************************
// init()
// ******************************************************************
function init() {
console.log("Connection websockets to:", ws_url);
connection = new WebSocket(ws_url, ['arduino']);
var mode = 0;
var ws2812fx_mode = 0;
$.getJSON("http://" + host + "/status", function(data) {
console.log("status", data);
mode = data.mode;
ws2812fx_mode = data.ws2812fx_mode;
$("#rng_delay").val(data.speed);
$("#rng_brightness").val(data.brightness);
$("#rng_white").val(data.color[0]);
$("#rng_red").val(data.color[1]);
$("#rng_green").val(data.color[2]);
$("#rng_blue").val(data.color[3]);
var statusColor = "#" + componentToHex(data.color[1]) + componentToHex(data.color[2]) + componentToHex(data.color[3]);
$('#status').css("backgroundColor", statusColor);
$('#status_color').text(statusColor + "- R=" + data.color[1] + ", G=" + data.color[2] + ", B=" + data.color[3]);
});
// Load modes async
// List of all color modes
// enum MODE {OFF, AUTO, TV, E131, SET_MODE, HOLD, CUSTOM, SETCOLOR, SETSPEED, BRIGHTNESS, WIPE, RAINBOW, RAINBOWCYCLE, THEATERCHASE, TWINKLERANDOM, THEATERCHASERAINBOW};
$.getJSON("http://" + host + "/get_modes", function(data) {
console.log("modes", data);
var modes_html = "";
data.forEach(function(current_mode){
if (current_mode.mode !== undefined) {
modes_html += '<div class="col s12 m6 l6 btn_grid">';
if ((mode == "5" && current_mode.mode == ws2812fx_mode) || (mode == "0" && current_mode.mode == "off") || (mode == "2" && current_mode.mode == "tv") || (mode == "3" && current_mode.mode == "e131")){
modes_html += '<a class="btn waves-effect waves-light btn_mode red" name="action" data-mode="' + current_mode.mode + '">(' + current_mode.mode +') '+ current_mode.name;
} else {
modes_html += '<a class="btn waves-effect waves-light btn_mode blue" name="action" data-mode="' + current_mode.mode + '">(' + current_mode.mode +') '+ current_mode.name;
}
modes_html += '<i class="material-icons right">send</i>';
modes_html += '</a>';
modes_html += '</div>';
}
});
$('#modes').html(modes_html);
});
// When the connection is open, send some data to the server
connection.onopen = function () {
//connection.send('Ping'); // Send the message 'Ping' to the server
console.log('WebSocket Open');
showPane('pane1');
};
// Log errors
connection.onerror = function (error) {
console.log('WebSocket Error ' + error);
$('#mc-wsloader').addClass('hide');
$('#mc-wserror').removeClass('hide');
};
// Log messages from the server
connection.onmessage = function (e) {
console.log('WebSocket from server: ' + e.data);
ws_waiting = 0;
};
}
// ******************************************************************
// Modes
// ******************************************************************
$("#pane2").on("click", ".btn_mode", function() {
var mode = $(this).attr("data-mode");
last_mode = mode;
var btn = $(this);
setMode(mode, function() {
$(".btn_mode, .btn_mode_static").removeClass("red").addClass("blue");
btn.removeClass("blue").addClass("red");
});
});
$("#pane2").on("click", ".btn_mode_static", function() {
var mode = $(this).attr("data-mode");
var btn = $(this);
wsSendCommand("=" + mode);
$(".btn_mode, .btn_mode_static").removeClass("red").addClass("blue");
btn.removeClass("blue").addClass("red");
});
$("#pane2").on("change", ".update_colors", setMainColor);
$("#pane2").on("change", ".update_delay", function() {
var delay = $("#rng_delay").val();
wsSendCommand("?" + delay);
});
$("#pane2").on("change", ".update_brightness", function() {
var brightness = $("#rng_brightness").val();
wsSendCommand("%" + brightness);
});
$("#autoSwitch").on("change", function () {
if ($(this).prop('checked')) {
wsSendCommand("start");
} else {
wsSendCommand("stop");
}
});
function setMode(mode, finish_funtion) {
console.log("Mode: ", mode);
wsSendCommand("/" + mode);
finish_funtion();
}
function setMainColor() {
var white = $("#rng_white").val();
var red = $("#rng_red").val();
var green = $("#rng_green").val();
var blue = $("#rng_blue").val();
var hexColor = componentToHex(white) + componentToHex(red) + componentToHex(green) + componentToHex(blue);
var statusColor = "#" + componentToHex(red) + componentToHex(green) + componentToHex(blue);
wsSetMainColor(hexColor);
$('#status').css("backgroundColor", statusColor);
$('#status_color').text(statusColor + "- R=" + red + ", G=" + green + ", B=" + blue);
}
// ******************************************************************
// WebSocket commands
// ******************************************************************
function wsSendCommand(cmd) {
console.log("Send WebSocket command:", cmd);
if (ws_waiting == 0) {
connection.send(cmd);
ws_waiting++;
} else {
console.log("++++++++ WS call waiting, skip")
}
}
function wsSetAll(hexColor) {
console.log("wsSetAll() Set all colors to:", hexColor);
wsSendCommand("*" + hexColor);
}
function wsSetMainColor(hexColor) {
console.log("wsSetMainColor() Set main colors to:", hexColor);
wsSendCommand("#" + hexColor);
}
// ******************************************************************
// Colorwheel
// ******************************************************************
// this is supposed to work on mobiles (touch) as well as on a desktop (click)
// since we couldn't find a decent one .. this try of writing one by myself
// + google. swiping would be really nice - I will possibly implement it with
// jquery later - or never.
var canvas = document.getElementById("myCanvas");
// FIX: Cancel touch end event and handle click via touchstart
// canvas.addEventListener("touchend", function(e) { e.preventDefault(); }, false);
canvas.addEventListener("touchmove", doTouch, false);
canvas.addEventListener("click", doClick, false);
//canvas.addEventListener("mousemove", doClick, false);
var context = canvas.getContext('2d');
var centerX = canvas.width / 2;
var centerY = canvas.height / 2;
var innerRadius = canvas.width / 4.5;
var outerRadius = (canvas.width - 10) / 2
//outer border
context.beginPath();
//outer circle
context.arc(centerX, centerY, outerRadius, 0, 2 * Math.PI, false);
//draw the outer border: (gets drawn around the circle!)
context.lineWidth = 4;
context.strokeStyle = '#000000';
context.stroke();
context.closePath();
//fill with beautiful colors
//taken from here: http://stackoverflow.com/questions/18265804/building-a-color-wheel-in-html5
for(var angle=0; angle<=360; angle+=1) {
var startAngle = (angle-2)*Math.PI/180;
var endAngle = angle * Math.PI/180;
context.beginPath();
context.moveTo(centerX, centerY);
context.arc(centerX, centerY, outerRadius, startAngle, endAngle, false);
context.closePath();
context.fillStyle = 'hsl('+angle+', 100%, 50%)';
context.fill();
context.closePath();
}
//inner border
context.beginPath();
//context.arc(centerX, centerY, radius, startAngle, endAngle, counterClockwise);
context.arc(centerX, centerY, innerRadius, 0, 2 * Math.PI, false);
//fill the center
var my_gradient=context.createLinearGradient(0,0,170,0);
my_gradient.addColorStop(0,"black");
my_gradient.addColorStop(1,"white");
context.fillStyle = my_gradient;
context.fillStyle = "white";
context.fill();
//draw the inner line
context.lineWidth = 2;
context.strokeStyle = '#000000';
context.stroke();
context.closePath();
//get Mouse x/y canvas position
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
//comp to Hex
function componentToHex(c) {
//var hex = c.toString(16);
//return hex.length == 1 ? "0" + hex : hex;
return ("0"+(Number(c).toString(16))).slice(-2).toUpperCase();
}
//rgb/rgba to Hex
function rgbToHex(rgb) {
return componentToHex(rgb[0]) + componentToHex(rgb[1]) + componentToHex(rgb[2]);
}
//display the touch/click position and color info
function updateStatus(pos, color) {
//var hexColor = rgbToHex(color);
//wsSetAll(hexColor);
var hexColor = componentToHex(color[0]) + componentToHex(color[1]) + componentToHex(color[2]);
wsSetMainColor(hexColor);
hexColor = "#" + hexColor;
$('#status').css("backgroundColor", hexColor);
$('#status_color').text(hexColor + " - R=" + color[0] + ", G=" + color[1] + ", B=" + color[2]);
$('#status_pos').text("x: " + pos.x + " - y: " + pos.y);
$("#rng_white").val(0);
$("#rng_red").val(color[0]);
$("#rng_green").val(color[1]);
$("#rng_blue").val(color[2]);
}
//handle the touch event
function doTouch(event) {
//to not also fire on click
event.preventDefault();
var el = event.target;
//touch position
var pos = {x: Math.round(event.targetTouches[0].pageX - el.offsetLeft),
y: Math.round(event.targetTouches[0].pageY - el.offsetTop)};
//color
var color = context.getImageData(pos.x, pos.y, 1, 1).data;
updateStatus(pos, color);
}
function doClick(event) {
//click position
var pos = getMousePos(canvas, event);
//color
var color = context.getImageData(pos.x, pos.y, 1, 1).data;
//console.log("click", pos.x, pos.y, color);
updateStatus(pos, color);
//now do sth with the color rgbToHex(color);
//don't do stuff when #000000 (outside circle and lines
}
// ******************************************************************
// main
// ******************************************************************
init();
}); // end of document ready
})(jQuery); // end of jQuery name space
-4
View File
@@ -1,4 +0,0 @@
## Retired, use:
McLightingHTML from https://github.com/FabLab-Luenen/McLightingHTML
or set #define USE_HTML_MIN_GZ in definitions.h to use the integrated!
-466
View File
@@ -1,466 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<!--Import Google Icon Font-->
<link href="http://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<!--Import materialize.css-->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/css/materialize.min.css" media="screen,projection" />
<!--Let browser know website is optimized for mobile-->
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
<meta name="mobile-web-app-capable" content="yes">
<meta charset="utf-8"/>
<title>McLighting v2</title>
</head>
<body>
<nav class="blue light-blueXXX lighten-1XXX" role="navigation" id="mc-nav">
<div class="nav-wrapper container">
<a id="logo-container" href="#" class="brand-logo">Mc Lighting v2</a>
<ul class="right hide-on-med-and-down">
<li><a href="#" class="mc-navlink" data-pane="pane1">Wheel</a></li>
<li><a href="#" class="mc-navlink" data-pane="pane2">Modes</a></li>
</ul>
<ul id="nav-mobile" class="side-nav">
<li><a href="#" class="mc-navlink" data-pane="pane1">Wheel</a></li>
<li><a href="#" class="mc-navlink" data-pane="pane2">Modes</a></li>
</ul>
<a href="#" data-activates="nav-mobile" class="button-collapse"><i class="material-icons">menu</i></a>
</div>
</nav>
<div class="container mc_pane" id="pane0">
<div class="section">
<div class="row" id="mc-wsloader">
<div class="col">
<div class="preloader-wrapper active">
<div class="spinner-layer spinner-blue-only">
<div class="circle-clipper left">
<div class="circle"></div>
</div>
<div class="gap-patch">
<div class="circle"></div>
</div>
<div class="circle-clipper right">
<div class="circle"></div>
</div>
</div>
</div>
</div>
</div>
<div class="row hide" id="mc-wserror">
<div class="col">
<div>Error on websocket connect.</div>
</div>
</div>
</div>
</div>
<div class="container mc_pane hide" id="pane1">
<div class="section">
<div class="row">
<div class="col s12 m6">
<div style="height: 330px; width: 330px;">
<canvas id="myCanvas" width="330" height="330" style="-webkit-user-select: none;-webkit-tap-highlight-color: rgba(0,0,0,0);-moz-user-select:none;"></canvas>
</div>
</div>
<div class="col s12 m6">
<div class="card-panel" id="status">
<div id="status_pos">pick a color</div>
<div id="status_color"></div>
</div>
</div>
<div class="col s12 m6">
<div class="right switch">Auto:<br>
<label>Off
<input id="autoSwitch" type="checkbox"><span class="lever"></span>On
</label>
</div>
</div>
</div>
</div>
</div>
<div class="container mc_pane hide" id="pane2">
<div class="section">
<div class="row">
<form class="col s12">
<div class="row">
<div class="input-field col s12 l4">
<label for="txt_red">Red</label><br/>
<p class="range-field"><input type="range" id="rng_red" min="0" max="255" class="update_colors" /></p>
</div>
<div class="input-field col s12 l4">
<label for="txt_green">Green</label><br/>
<p class="range-field"><input type="range" id="rng_green" min="0" max="255" class="update_colors" /></p>
</div>
<div class="input-field col s12 l4">
<label for="txt_blue">Blue</label><br/>
<p class="range-field"><input type="range" id="rng_blue" min="0" max="255" class="update_colors" /></p>
</div>
</div>
<div class="row">
<div class="input-field col s12">
<label for="txt_delay">Speed</label><br/>
<p class="range-field"><input type="range" id="rng_delay" min="0" max="255" value="196" class="update_delay" /></p>
</div>
</div>
<div class="row">
<div class="input-field col s12">
<label for="txt_delay">Brightness</label><br/>
<p class="range-field"><input type="range" id="rng_brightness" min="0" max="255" value="196" class="update_brightness" /></p>
</div>
</div>
</form>
</div>
<div class="row">
<div class="col s12 m6 l6 btn_grid">
<a class="btn waves-effect waves-light btn_mode_static blue" name="action" data-mode="off">OFF
<i class="material-icons right">send</i>
</a>
</div>
<div class="col s12 m6 l6 btn_grid">
<a class="btn waves-effect waves-light btn_mode_static blue" name="action" data-mode="tv">TV
<i class="material-icons right">send</i>
</a>
</div>
<div id="modes">
<div class="input-field col s12">
Loading animations...
</div>
</div>
</div>
</div>
</div>
<footer class="page-footer blue">
<div class="footer-copyright">
<div class="container">© 2017
<a class="grey-text text-lighten-4 right" href="https://github.com/toblum/McLighting">Project home</a>
</div>
</div>
</footer>
<style type="text/css">
.btn_grid {
margin: 7px 0;
}
</style>
<!--Import jQuery before materialize.js-->
<script type="text/javascript" src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/js/materialize.min.js"></script>
<script type="text/javascript">(function($){
$(function(){
// Settings
var host = window.location.hostname;
//host = "esp8266_02.local";
var ws_url = 'ws://' + host + ':81';
var connection;
var ws_waiting = 0;
// ******************************************************************
// Side navigation
// ******************************************************************
$('.button-collapse').sideNav();
// Navlinks
$('#mc-nav').on('click', '.mc-navlink', function(){
console.log("Navigate to pane: ", $(this).data("pane"));
showPane($(this).data("pane"));
});
function showPane(pane) {
$('.mc_pane').addClass('hide');
$('#' + pane).removeClass('hide');
$('.button-collapse').sideNav('hide');
if (pane == "pane2") {
setMainColor();
}
}
// ******************************************************************
// init()
// ******************************************************************
function init() {
console.log("Connection websockets to:", ws_url);
connection = new WebSocket(ws_url, ['arduino']);
// Load modes async
$.getJSON("http://" + host + "/get_modes", function(data) {
//console.log("modes", data);
var modes_html = "";
data.forEach(function(current_mode){
if (current_mode.mode !== undefined) {
modes_html += '<div class="col s12 m6 l6 btn_grid">';
modes_html += '<a class="btn waves-effect waves-light btn_mode blue" name="action" data-mode="' + current_mode.mode + '">(' + current_mode.mode +') '+ current_mode.name;
modes_html += '<i class="material-icons right">send</i>';
modes_html += '</a>';
modes_html += '</div>';
}
});
$('#modes').html(modes_html);
});
// When the connection is open, send some data to the server
connection.onopen = function () {
//connection.send('Ping'); // Send the message 'Ping' to the server
console.log('WebSocket Open');
showPane('pane1');
};
// Log errors
connection.onerror = function (error) {
console.log('WebSocket Error ' + error);
$('#mc-wsloader').addClass('hide');
$('#mc-wserror').removeClass('hide');
};
// Log messages from the server
connection.onmessage = function (e) {
console.log('WebSocket from server: ' + e.data);
ws_waiting = 0;
};
}
// ******************************************************************
// Modes
// ******************************************************************
$("#pane2").on("click", ".btn_mode", function() {
var mode = $(this).attr("data-mode");
last_mode = mode;
var btn = $(this);
setMode(mode, function() {
$(".btn_mode, .btn_mode_static").removeClass("red").addClass("blue");
btn.removeClass("blue").addClass("red");
});
});
$("#pane2").on("click", ".btn_mode_static", function() {
var mode = $(this).attr("data-mode");
var btn = $(this);
wsSendCommand("=" + mode);
$(".btn_mode, .btn_mode_static").removeClass("red").addClass("blue");
btn.removeClass("blue").addClass("red");
});
$("#pane2").on("change", ".update_colors", setMainColor);
$("#pane2").on("change", ".update_delay", function() {
var delay = $("#rng_delay").val();
wsSendCommand("?" + delay);
});
$("#pane2").on("change", ".update_brightness", function() {
var brightness = $("#rng_brightness").val();
wsSendCommand("%" + brightness);
});
$("#autoSwitch").on("change", function () {
if ($(this).prop('checked')) {
wsSendCommand("start");
} else {
wsSendCommand("stop");
}
});
function setMode(mode, finish_funtion) {
console.log("Mode: ", mode);
wsSendCommand("/" + mode);
finish_funtion();
}
function setMainColor() {
var red = $("#rng_red").val();
var green = $("#rng_green").val();
var blue = $("#rng_blue").val();
var mainColorHex = componentToHex(red) + componentToHex(green) + componentToHex(blue);
wsSetMainColor(mainColorHex);
}
// ******************************************************************
// WebSocket commands
// ******************************************************************
function wsSendCommand(cmd) {
console.log("Send WebSocket command:", cmd);
if (ws_waiting == 0) {
connection.send(cmd);
ws_waiting++;
} else {
console.log("++++++++ WS call waiting, skip")
}
}
function wsSetAll(hexColor) {
console.log("wsSetAll() Set all colors to:", hexColor);
wsSendCommand("*" + hexColor);
}
function wsSetMainColor(hexColor) {
console.log("wsSetMainColor() Set main colors to:", hexColor);
wsSendCommand("#" + hexColor);
}
// ******************************************************************
// Colorwheel
// ******************************************************************
// this is supposed to work on mobiles (touch) as well as on a desktop (click)
// since we couldn't find a decent one .. this try of writing one by myself
// + google. swiping would be really nice - I will possibly implement it with
// jquery later - or never.
var canvas = document.getElementById("myCanvas");
// FIX: Cancel touch end event and handle click via touchstart
// canvas.addEventListener("touchend", function(e) { e.preventDefault(); }, false);
canvas.addEventListener("touchmove", doTouch, false);
canvas.addEventListener("click", doClick, false);
//canvas.addEventListener("mousemove", doClick, false);
var context = canvas.getContext('2d');
var centerX = canvas.width / 2;
var centerY = canvas.height / 2;
var innerRadius = canvas.width / 4.5;
var outerRadius = (canvas.width - 10) / 2
//outer border
context.beginPath();
//outer circle
context.arc(centerX, centerY, outerRadius, 0, 2 * Math.PI, false);
//draw the outer border: (gets drawn around the circle!)
context.lineWidth = 4;
context.strokeStyle = '#000000';
context.stroke();
context.closePath();
//fill with beautiful colors
//taken from here: http://stackoverflow.com/questions/18265804/building-a-color-wheel-in-html5
for(var angle=0; angle<=360; angle+=1) {
var startAngle = (angle-2)*Math.PI/180;
var endAngle = angle * Math.PI/180;
context.beginPath();
context.moveTo(centerX, centerY);
context.arc(centerX, centerY, outerRadius, startAngle, endAngle, false);
context.closePath();
context.fillStyle = 'hsl('+angle+', 100%, 50%)';
context.fill();
context.closePath();
}
//inner border
context.beginPath();
//context.arc(centerX, centerY, radius, startAngle, endAngle, counterClockwise);
context.arc(centerX, centerY, innerRadius, 0, 2 * Math.PI, false);
//fill the center
var my_gradient=context.createLinearGradient(0,0,170,0);
my_gradient.addColorStop(0,"black");
my_gradient.addColorStop(1,"white");
context.fillStyle = my_gradient;
context.fillStyle = "white";
context.fill();
//draw the inner line
context.lineWidth = 2;
context.strokeStyle = '#000000';
context.stroke();
context.closePath();
//get Mouse x/y canvas position
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
//comp to Hex
function componentToHex(c) {
//var hex = c.toString(16);
//return hex.length == 1 ? "0" + hex : hex;
return ("0"+(Number(c).toString(16))).slice(-2).toUpperCase();
}
//rgb/rgba to Hex
function rgbToHex(rgb) {
return componentToHex(rgb[0]) + componentToHex(rgb[1]) + componentToHex(rgb[2]);
}
//display the touch/click position and color info
function updateStatus(pos, color) {
var hexColor = rgbToHex(color);
wsSetAll(hexColor);
hexColor = "#" + hexColor;
$('#status').css("backgroundColor", hexColor);
$('#status_color').text(hexColor + " - R=" + color[0] + ", G=" + color[1] + ", B=" + color[2]);
$('#status_pos').text("x: " + pos.x + " - y: " + pos.y);
$("#rng_red").val(color[0]);
$("#rng_green").val(color[1]);
$("#rng_blue").val(color[2]);
}
//handle the touch event
function doTouch(event) {
//to not also fire on click
event.preventDefault();
var el = event.target;
//touch position
var pos = {x: Math.round(event.targetTouches[0].pageX - el.offsetLeft),
y: Math.round(event.targetTouches[0].pageY - el.offsetTop)};
//color
var color = context.getImageData(pos.x, pos.y, 1, 1).data;
updateStatus(pos, color);
}
function doClick(event) {
//click position
var pos = getMousePos(canvas, event);
//color
var color = context.getImageData(pos.x, pos.y, 1, 1).data;
//console.log("click", pos.x, pos.y, color);
updateStatus(pos, color);
//now do sth with the color rgbToHex(color);
//don't do stuff when #000000 (outside circle and lines
}
// ******************************************************************
// main
// ******************************************************************
init();
}); // end of document ready
})(jQuery); // end of jQuery name space</script>
</body>
</html>
-55
View File
@@ -1,55 +0,0 @@
var gulp = require('gulp'),
request = require('request'),
fs = require('fs'),
connect = require('gulp-connect'),
fileinclude = require('gulp-file-include');
var src_dir = "src/";
var build_dir = "build/";
gulp.task('html', function() {
gulp.src(src_dir + '*.htm')
.pipe(fileinclude({
prefix: '@@',
basepath: '@file'
}))
.pipe(gulp.dest('build'))
.pipe(connect.reload());
});
gulp.task('connect', function() {
connect.server({
root: 'build',
livereload: true
});
});
gulp.task('watch', function() {
gulp.watch(src_dir + '*.htm', ['html']);
gulp.watch(src_dir + 'js/*.js', ['html']);
});
gulp.task('upload', ['html'], function() {
var url = 'http://192.168.0.49/edit';
var options = {
url: url,
headers: {
'Content-Type': 'multipart/form-data'
}
};
var r = request.post(options, function optionalCallback(err, httpResponse, body) {
if (err) {
return console.error('upload failed:', err);
}
console.log('Upload successful! Server responded with:', body);
});
var form = r.form();
form.append('data', fs.createReadStream(__dirname + "/" + build_dir + '/index.htm'), {filename: '/index.htm', contentType: "application/octet-stream"});
});
gulp.task('default', ['html']);
gulp.task('serve', ['watch', 'connect']);
-18
View File
@@ -1,18 +0,0 @@
{
"name": "mc_lighting",
"version": "2.0.0",
"description": "Web client for Mc Lighting",
"main": "index.html",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Tobias Blum",
"license": "MIT",
"dependencies": {
"fs": "0.0.2",
"gulp": "^3.9.1",
"gulp-connect": "^5.0.0",
"gulp-file-include": "^1.0.0",
"request": "^2.72.0"
}
}
-162
View File
@@ -1,162 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<!--Import Google Icon Font-->
<link href="http://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<!--Import materialize.css-->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/css/materialize.min.css" media="screen,projection" />
<!--Let browser know website is optimized for mobile-->
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
<meta name="mobile-web-app-capable" content="yes">
<meta charset="utf-8"/>
<title>McLighting v2</title>
</head>
<body>
<nav class="blue light-blueXXX lighten-1XXX" role="navigation" id="mc-nav">
<div class="nav-wrapper container">
<a id="logo-container" href="#" class="brand-logo">Mc Lighting v2</a>
<ul class="right hide-on-med-and-down">
<li><a href="#" class="mc-navlink" data-pane="pane1">Wheel</a></li>
<li><a href="#" class="mc-navlink" data-pane="pane2">Modes</a></li>
</ul>
<ul id="nav-mobile" class="side-nav">
<li><a href="#" class="mc-navlink" data-pane="pane1">Wheel</a></li>
<li><a href="#" class="mc-navlink" data-pane="pane2">Modes</a></li>
</ul>
<a href="#" data-activates="nav-mobile" class="button-collapse"><i class="material-icons">menu</i></a>
</div>
</nav>
<div class="container mc_pane" id="pane0">
<div class="section">
<div class="row" id="mc-wsloader">
<div class="col">
<div class="preloader-wrapper active">
<div class="spinner-layer spinner-blue-only">
<div class="circle-clipper left">
<div class="circle"></div>
</div>
<div class="gap-patch">
<div class="circle"></div>
</div>
<div class="circle-clipper right">
<div class="circle"></div>
</div>
</div>
</div>
</div>
</div>
<div class="row hide" id="mc-wserror">
<div class="col">
<div>Error on websocket connect.</div>
</div>
</div>
</div>
</div>
<div class="container mc_pane hide" id="pane1">
<div class="section">
<div class="row">
<div class="col s12 m6">
<div style="height: 330px; width: 330px;">
<canvas id="myCanvas" width="330" height="330" style="-webkit-user-select: none;-webkit-tap-highlight-color: rgba(0,0,0,0);-moz-user-select:none;"></canvas>
</div>
</div>
<div class="col s12 m6">
<div class="card-panel" id="status">
<div id="status_pos">pick a color</div>
<div id="status_color"></div>
</div>
</div>
<div class="col s12 m6">
<div class="right switch">Auto:<br>
<label>Off
<input id="autoSwitch" type="checkbox"><span class="lever"></span>On
</label>
</div>
</div>
</div>
</div>
</div>
<div class="container mc_pane hide" id="pane2">
<div class="section">
<div class="row">
<form class="col s12">
<div class="row">
<div class="input-field col s12 l4">
<label for="txt_red">Red</label><br/>
<p class="range-field"><input type="range" id="rng_red" min="0" max="255" class="update_colors" /></p>
</div>
<div class="input-field col s12 l4">
<label for="txt_green">Green</label><br/>
<p class="range-field"><input type="range" id="rng_green" min="0" max="255" class="update_colors" /></p>
</div>
<div class="input-field col s12 l4">
<label for="txt_blue">Blue</label><br/>
<p class="range-field"><input type="range" id="rng_blue" min="0" max="255" class="update_colors" /></p>
</div>
</div>
<div class="row">
<div class="input-field col s12">
<label for="txt_delay">Speed</label><br/>
<p class="range-field"><input type="range" id="rng_delay" min="0" max="255" value="196" class="update_delay" /></p>
</div>
</div>
<div class="row">
<div class="input-field col s12">
<label for="txt_delay">Brightness</label><br/>
<p class="range-field"><input type="range" id="rng_brightness" min="0" max="255" value="196" class="update_brightness" /></p>
</div>
</div>
</form>
</div>
<div class="row">
<div class="col s12 m6 l6 btn_grid">
<a class="btn waves-effect waves-light btn_mode_static blue" name="action" data-mode="off">OFF
<i class="material-icons right">send</i>
</a>
</div>
<div class="col s12 m6 l6 btn_grid">
<a class="btn waves-effect waves-light btn_mode_static blue" name="action" data-mode="tv">TV
<i class="material-icons right">send</i>
</a>
</div>
<div id="modes">
<div class="input-field col s12">
Loading animations...
</div>
</div>
</div>
</div>
</div>
<footer class="page-footer blue">
<div class="footer-copyright">
<div class="container">© 2017
<a class="grey-text text-lighten-4 right" href="https://github.com/toblum/McLighting">Project home</a>
</div>
</div>
</footer>
<style type="text/css">
.btn_grid {
margin: 7px 0;
}
</style>
<!--Import jQuery before materialize.js-->
<script type="text/javascript" src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/js/materialize.min.js"></script>
<script type="text/javascript">@@include('js/script.js')</script>
</body>
</html>
-305
View File
@@ -1,305 +0,0 @@
(function($){
$(function(){
// Settings
var host = window.location.hostname;
//host = "esp8266_02.local";
var ws_url = 'ws://' + host + ':81';
var connection;
var ws_waiting = 0;
// ******************************************************************
// Side navigation
// ******************************************************************
$('.button-collapse').sideNav();
// Navlinks
$('#mc-nav').on('click', '.mc-navlink', function(){
console.log("Navigate to pane: ", $(this).data("pane"));
showPane($(this).data("pane"));
});
function showPane(pane) {
$('.mc_pane').addClass('hide');
$('#' + pane).removeClass('hide');
$('.button-collapse').sideNav('hide');
if (pane == "pane2") {
setMainColor();
}
}
// ******************************************************************
// init()
// ******************************************************************
function init() {
console.log("Connection websockets to:", ws_url);
connection = new WebSocket(ws_url, ['arduino']);
// Load modes async
$.getJSON("http://" + host + "/get_modes", function(data) {
//console.log("modes", data);
var modes_html = "";
data.forEach(function(current_mode){
if (current_mode.mode !== undefined) {
modes_html += '<div class="col s12 m6 l6 btn_grid">';
modes_html += '<a class="btn waves-effect waves-light btn_mode blue" name="action" data-mode="' + current_mode.mode + '">(' + current_mode.mode +') '+ current_mode.name;
modes_html += '<i class="material-icons right">send</i>';
modes_html += '</a>';
modes_html += '</div>';
}
});
$('#modes').html(modes_html);
});
// When the connection is open, send some data to the server
connection.onopen = function () {
//connection.send('Ping'); // Send the message 'Ping' to the server
console.log('WebSocket Open');
showPane('pane1');
};
// Log errors
connection.onerror = function (error) {
console.log('WebSocket Error ' + error);
$('#mc-wsloader').addClass('hide');
$('#mc-wserror').removeClass('hide');
};
// Log messages from the server
connection.onmessage = function (e) {
console.log('WebSocket from server: ' + e.data);
ws_waiting = 0;
};
}
// ******************************************************************
// Modes
// ******************************************************************
$("#pane2").on("click", ".btn_mode", function() {
var mode = $(this).attr("data-mode");
last_mode = mode;
var btn = $(this);
setMode(mode, function() {
$(".btn_mode, .btn_mode_static").removeClass("red").addClass("blue");
btn.removeClass("blue").addClass("red");
});
});
$("#pane2").on("click", ".btn_mode_static", function() {
var mode = $(this).attr("data-mode");
var btn = $(this);
wsSendCommand("=" + mode);
$(".btn_mode, .btn_mode_static").removeClass("red").addClass("blue");
btn.removeClass("blue").addClass("red");
});
$("#pane2").on("change", ".update_colors", setMainColor);
$("#pane2").on("change", ".update_delay", function() {
var delay = $("#rng_delay").val();
wsSendCommand("?" + delay);
});
$("#pane2").on("change", ".update_brightness", function() {
var brightness = $("#rng_brightness").val();
wsSendCommand("%" + brightness);
});
$("#autoSwitch").on("change", function () {
if ($(this).prop('checked')) {
wsSendCommand("start");
} else {
wsSendCommand("stop");
}
});
function setMode(mode, finish_funtion) {
console.log("Mode: ", mode);
wsSendCommand("/" + mode);
finish_funtion();
}
function setMainColor() {
var red = $("#rng_red").val();
var green = $("#rng_green").val();
var blue = $("#rng_blue").val();
var mainColorHex = componentToHex(red) + componentToHex(green) + componentToHex(blue);
wsSetMainColor(mainColorHex);
}
// ******************************************************************
// WebSocket commands
// ******************************************************************
function wsSendCommand(cmd) {
console.log("Send WebSocket command:", cmd);
if (ws_waiting == 0) {
connection.send(cmd);
ws_waiting++;
} else {
console.log("++++++++ WS call waiting, skip")
}
}
function wsSetAll(hexColor) {
console.log("wsSetAll() Set all colors to:", hexColor);
wsSendCommand("*" + hexColor);
}
function wsSetMainColor(hexColor) {
console.log("wsSetMainColor() Set main colors to:", hexColor);
wsSendCommand("#" + hexColor);
}
// ******************************************************************
// Colorwheel
// ******************************************************************
// this is supposed to work on mobiles (touch) as well as on a desktop (click)
// since we couldn't find a decent one .. this try of writing one by myself
// + google. swiping would be really nice - I will possibly implement it with
// jquery later - or never.
var canvas = document.getElementById("myCanvas");
// FIX: Cancel touch end event and handle click via touchstart
// canvas.addEventListener("touchend", function(e) { e.preventDefault(); }, false);
canvas.addEventListener("touchmove", doTouch, false);
canvas.addEventListener("click", doClick, false);
//canvas.addEventListener("mousemove", doClick, false);
var context = canvas.getContext('2d');
var centerX = canvas.width / 2;
var centerY = canvas.height / 2;
var innerRadius = canvas.width / 4.5;
var outerRadius = (canvas.width - 10) / 2
//outer border
context.beginPath();
//outer circle
context.arc(centerX, centerY, outerRadius, 0, 2 * Math.PI, false);
//draw the outer border: (gets drawn around the circle!)
context.lineWidth = 4;
context.strokeStyle = '#000000';
context.stroke();
context.closePath();
//fill with beautiful colors
//taken from here: http://stackoverflow.com/questions/18265804/building-a-color-wheel-in-html5
for(var angle=0; angle<=360; angle+=1) {
var startAngle = (angle-2)*Math.PI/180;
var endAngle = angle * Math.PI/180;
context.beginPath();
context.moveTo(centerX, centerY);
context.arc(centerX, centerY, outerRadius, startAngle, endAngle, false);
context.closePath();
context.fillStyle = 'hsl('+angle+', 100%, 50%)';
context.fill();
context.closePath();
}
//inner border
context.beginPath();
//context.arc(centerX, centerY, radius, startAngle, endAngle, counterClockwise);
context.arc(centerX, centerY, innerRadius, 0, 2 * Math.PI, false);
//fill the center
var my_gradient=context.createLinearGradient(0,0,170,0);
my_gradient.addColorStop(0,"black");
my_gradient.addColorStop(1,"white");
context.fillStyle = my_gradient;
context.fillStyle = "white";
context.fill();
//draw the inner line
context.lineWidth = 2;
context.strokeStyle = '#000000';
context.stroke();
context.closePath();
//get Mouse x/y canvas position
function getMousePos(canvas, evt) {
var rect = canvas.getBoundingClientRect();
return {
x: evt.clientX - rect.left,
y: evt.clientY - rect.top
};
}
//comp to Hex
function componentToHex(c) {
//var hex = c.toString(16);
//return hex.length == 1 ? "0" + hex : hex;
return ("0"+(Number(c).toString(16))).slice(-2).toUpperCase();
}
//rgb/rgba to Hex
function rgbToHex(rgb) {
return componentToHex(rgb[0]) + componentToHex(rgb[1]) + componentToHex(rgb[2]);
}
//display the touch/click position and color info
function updateStatus(pos, color) {
var hexColor = rgbToHex(color);
wsSetAll(hexColor);
hexColor = "#" + hexColor;
$('#status').css("backgroundColor", hexColor);
$('#status_color').text(hexColor + " - R=" + color[0] + ", G=" + color[1] + ", B=" + color[2]);
$('#status_pos').text("x: " + pos.x + " - y: " + pos.y);
$("#rng_red").val(color[0]);
$("#rng_green").val(color[1]);
$("#rng_blue").val(color[2]);
}
//handle the touch event
function doTouch(event) {
//to not also fire on click
event.preventDefault();
var el = event.target;
//touch position
var pos = {x: Math.round(event.targetTouches[0].pageX - el.offsetLeft),
y: Math.round(event.targetTouches[0].pageY - el.offsetTop)};
//color
var color = context.getImageData(pos.x, pos.y, 1, 1).data;
updateStatus(pos, color);
}
function doClick(event) {
//click position
var pos = getMousePos(canvas, event);
//color
var color = context.getImageData(pos.x, pos.y, 1, 1).data;
//console.log("click", pos.x, pos.y, color);
updateStatus(pos, color);
//now do sth with the color rgbToHex(color);
//don't do stuff when #000000 (outside circle and lines
}
// ******************************************************************
// main
// ******************************************************************
init();
}); // end of document ready
})(jQuery); // end of jQuery name space