@@ -3,69 +3,42 @@ | |||
<head> | |||
<title>ESP8266 Treppenlicht</title> | |||
<!-- main style sheet --> | |||
<link href="/favicon.png" rel="icon" type="image/png" sizes="10x10"> | |||
<link href="/style.css" rel="stylesheet" type="text/css"> | |||
</head> | |||
<body> | |||
<div class="kopfzeile" style="text-align: center;"> | |||
<b>Treppenlicht</b> | |||
</div> | |||
<!-- | |||
<div class="ueberschrift"> | |||
Helligkeit | |||
label id="label_pwm"> | |||
</label> | |||
<div class="topbar">Treppenlicht</div> | |||
<div class="param_block"> | |||
Active Brightness: <output id="out_act_pwm" class="val_range">50</output> % | |||
<div class="slider"> | |||
<input type="range" class="regler" id="helligkeit" name="rangeInput" min="0" max="100" value="50" | |||
oninput="amount1.value=helligkeit.value"> | |||
<br> | |||
<output name="amount1" id="amount1" for="helligkeit">50</output> | |||
</div> | |||
</div>--> | |||
<form class="ueberschrift"> | |||
<div class="BridhgtnessInputGroup"> | |||
<label for="brightness"> Helligkeitswert in %:</label> | |||
<input id="brightness" type="number" name="brightness" step="1" min="0" max="100" placeholder="zB. 50" required> | |||
<span class="validity"></span> | |||
<button type="button" onclick="getInputValue()">Speichern</button> | |||
<script> | |||
function getInputValue(){ | |||
var helligkeit= document.getElementById("brightness").value; | |||
if (helligkeit > 100 | helligkeit < 0) | |||
alert("Helligkeit darf nicht groesser 100 oder kleiner 0 sein") | |||
else alert(helligkeit); | |||
} | |||
</script> | |||
<input type="range" class="regler" id="range_act_pwm" min="0" max="100" value="50"> | |||
</div> | |||
</form> | |||
</div> | |||
<!-- | |||
< div class="ueberschrift" > | |||
Helligkeit bei Dunkelheit | |||
< !--< label id = "label_pwm_dark" > | |||
</label > | |||
<div class="slider"> | |||
<input type="range" class="regler" id="helligkeit_dunkel" name="rangeInput" min="0" max="100" value="50" | |||
oninput="amount2.value=helligkeit_dunkel.value"> | |||
<br> | |||
<output name="amount2" id="amount2" for="helligkeit_dunkel">50</output> | |||
<div class="param_block"> | |||
Idle Brightness: <output id="out_idl_pwm" class="val_range">50</output> % | |||
<div class="slider"> | |||
<input type="range" class="regler" id="range_idl_pwm" min="0" max="100" value="50"> | |||
</div> | |||
</div> | |||
<div class="ueberschrift"> | |||
Laufgeschwindigkeit | |||
<!--<label id="label_geschwindigkeit"> | |||
</label> | |||
<div class="slider"> | |||
<input type="range" class="regler" id="geschwindigkeit" name="rangeInput" min="0" max="100" value="50" | |||
oninput="amount3.value=geschwindigkeit.value"> | |||
<br> | |||
<output name="amount3" id="amount3" for="geschwindigkeit">50</output> | |||
<div class="param_block"> | |||
Time per stair: <output id="out_tim_sta" class="val_range">50</output> % | |||
<div class="slider"> | |||
<input type="range" class="regler" id="range_tim_sta" min="0" max="100" value="50"> | |||
</div> | |||
</div> | |||
<div class="param_block"> | |||
On Time: <output id="out_tim_on" class="val_range">50</output> % | |||
<div class="slider"> | |||
<input type="range" class="regler" id="range_tim_on" min="0" max="100" value="50"> | |||
</div> | |||
</div> | |||
<div class="ueberschrift"> |
@@ -1,12 +1,54 @@ | |||
// var slider = document.getElementById("helligkeit"); | |||
// var output = document.getElementById("l_pwm"); | |||
// output.innerHTML = slider.value; // Display the default slider value | |||
let rangeValues = {}; | |||
let xhrUpd = new XMLHttpRequest(); | |||
// // Update the current slider value (each time you drag the slider handle) | |||
// slider.oninput = function() { | |||
// output.innerHTML = this.value; | |||
// } | |||
xhrUpd.onreadystatechange = function(){ | |||
if(xhrUpd.readyState == 4) { | |||
if (xhrUpd.status == 200){ | |||
console.log(xhrUpd.responseText); | |||
} | |||
else { | |||
console.log("status:", xhrUpd.status); | |||
} | |||
} | |||
} | |||
function reloadRangeValues() { | |||
let url = "/update"; | |||
// if there are scheduled updates, send them | |||
if(Object.keys(rangeValues).length > 0) { | |||
let params = []; | |||
for(let p in rangeValues) | |||
params.push(encodeURIComponent(p) + "=" + encodeURIComponent(rangeValues[p])); | |||
params = params.join("&"); | |||
xhrUpd.open("POST", url, true); | |||
xhrUpd.setRequestHeader('Content-type', 'application/x-www-form-urlencoded'); | |||
xhrUpd.send(params); | |||
rangeValues = {}; | |||
} | |||
setTimeout(reloadRangeValues, 1000); | |||
}; | |||
reloadRangeValues(); | |||
function sendRangeValue(range, val) { | |||
rangeValues[range] = val; | |||
console.log(rangeValues); | |||
}; | |||
// connect actions to range inputs | |||
function rangeToOutput(range, output) { | |||
document.getElementById(range).oninput = function() { | |||
document.getElementById(output).innerHTML = this.value; | |||
sendRangeValue(this.id, this.value); | |||
} | |||
} | |||
rangeToOutput("range_act_pwm", "out_act_pwm"); | |||
rangeToOutput("range_idl_pwm", "out_idl_pwm"); | |||
rangeToOutput("range_tim_sta", "out_tim_sta"); | |||
rangeToOutput("range_tim_on", "out_tim_on"); | |||
let xhr = new XMLHttpRequest(); | |||
@@ -26,15 +68,12 @@ xhr.onreadystatechange = function(){ | |||
} | |||
} | |||
} | |||
function reloadTerminal() { | |||
xhr.open("POST", "/app=terminal", true); | |||
xhr.open("POST", "/terminal", true); | |||
xhr.send(); | |||
setTimeout(reloadTerminal, 1000); | |||
}; | |||
reloadTerminal(); | |||
function clearTerminal() { | |||
document.getElementById("term").innerHTML = ''; | |||
} |
@@ -1,44 +1,44 @@ | |||
html { | |||
font-size: 16px; | |||
font-family: sans-serif, Arial, Helvetica; | |||
background-color: #d4d4d4; | |||
background-color: #ffffff; | |||
height: 100%; | |||
/* background-image: url('Background.png'); */ | |||
background-repeat: repeat; | |||
background-size: 150% 150%; | |||
} | |||
body { | |||
height: 100%; | |||
margin: 0 auto; | |||
border: none; | |||
border-radius: 3; | |||
} | |||
.topbar { | |||
padding: 1em; | |||
background-color: #1f1f1f; | |||
padding: 10px; | |||
background-color: #585858; | |||
color: white; | |||
font-size: x-large; | |||
font-size: xx-large; | |||
text-align: center; | |||
} | |||
.ueberschrift{ | |||
color: #ffffff; | |||
font-size: 50px; | |||
width: 100%; | |||
text-align: center; | |||
.param_block{ | |||
padding: 1em; | |||
color: #000000; | |||
border: 1px solid darkred; | |||
font-size: x-large; | |||
width: 80%; | |||
} | |||
.val_range { | |||
font-weight: bold; | |||
} | |||
.regler{ | |||
-webkit-appearance: none; | |||
height: 30px; | |||
/* -webkit-appearance: none; */ | |||
height: 50px; | |||
width: 100%; | |||
border-radius: 20px; | |||
outline: black; | |||
background-color: rgb(176, 188, 228); | |||
} | |||
.regler::-webkit-slider-thumb{ | |||
/* .regler::-webkit-slider-thumb{ | |||
-webkit-appearance: none; | |||
appearance: none; | |||
width: 5%; | |||
@@ -46,24 +46,53 @@ body { | |||
border-radius: 10px; | |||
background-color: rgb(107, 122, 192); | |||
cursor:pointer; | |||
} | |||
input[type=range]::-webkit-slider-thumb{ | |||
} */ | |||
/* input[type=range]::-webkit-slider-thumb{ | |||
-webkit-appearance: none; | |||
border:none; | |||
height: 30px; | |||
width: 4%; | |||
border-radius: 30px; | |||
} | |||
} */ | |||
.slider { | |||
width: 100%; | |||
margin: 1%; | |||
} | |||
.kopfzeile{ | |||
color: #1f1f1f; | |||
font-size: 50px; | |||
width: 100%; | |||
background-color: #8d8a8a; | |||
/*-------------------------------------------------------*/ | |||
/*Switch: | |||
.switch { | |||
position: relative; | |||
display: inline-block; | |||
width: 60px; | |||
height: 34px; | |||
} | |||
Hide default HTML checkbox | |||
.switch input { | |||
opacity: 0; | |||
width: 0; | |||
height: 0; | |||
} | |||
*/ | |||
/* The slider */ | |||
/*input:checked + .slider { | |||
background-color: #04AA6D; | |||
} | |||
input:focus + .slider { | |||
box-shadow: 0 0 1px #04AA6D; | |||
}*/ | |||
/* | |||
input:checked + .slider:before { | |||
-webkit-transform: translateX(26px); | |||
-ms-transform: translateX(26px); | |||
transform: translateX(26px); | |||
} | |||
*/ | |||
.terminal { | |||
margin:5%; |
@@ -1 +1 @@ | |||
Subproject commit 23e06c06a6026801a856141f64a6de54dd493b47 | |||
Subproject commit a70be39257e317d35e9118b385006a1e030e6452 |
@@ -121,8 +121,4 @@ void deleteFile(const char * path) { | |||
} else { | |||
Serial.println("Delete failed"); | |||
} | |||
} | |||
} |
@@ -3,7 +3,6 @@ | |||
#include <LittleFS.h> | |||
// some usefull wrappers for Filesystem | |||
bool mount_fs(); | |||
bool format_fs(); | |||
@@ -58,11 +58,28 @@ void HTTPServer::logt(const char *format, ...) { | |||
void HTTPServer::start_apps() { | |||
// application handler | |||
this->on("/app=terminal", HTTP_POST, [this]() { | |||
this->on("/update", HTTP_POST, [this]() { | |||
if(args()) { | |||
for(int i=0; i<args()-1; i++) { | |||
Serial.printf("%s=%s\n", argName(i).c_str(), arg(i).c_str()); | |||
if(argName(i).equals("range_idl_pwm")) { | |||
treppe->set_idle_prozent(arg(i).toInt()); | |||
} | |||
} | |||
} | |||
send(200, "text/plain", "accepted"); | |||
}); | |||
this->on("/terminal", HTTP_POST, [this]() { | |||
// Serial.printf("got /terminal\n"); | |||
if(tbuf_head) { | |||
send(200, "text/plain", tbuf); | |||
tbuf_head = 0; | |||
} | |||
else { | |||
send(202, "text/plain", ""); | |||
} | |||
}); | |||
} |
@@ -5,6 +5,7 @@ | |||
#include <ESP8266WebServer.h> | |||
#include <stdarg.h> | |||
#include "filesys.h" | |||
#include "treppe.h" | |||
// debug log <ESP8266WebServer.h> | |||
// #define DEBUGV(f,...) do { Serial.printf(PSTR(f), ##__VA_ARGS__); } while (0) | |||
@@ -24,10 +25,11 @@ private: | |||
void listRoot() { | |||
ls(rootDir); | |||
} | |||
Treppe* treppe; | |||
public: | |||
HTTPServer(const int _port, const char* _rootDir) : | |||
ESP8266WebServer(_port), rootDir(_rootDir) | |||
HTTPServer(const int _port, const char* _rootDir, Treppe* _treppe) : | |||
ESP8266WebServer(_port), rootDir(_rootDir), treppe(_treppe) | |||
{ } | |||
~HTTPServer() | |||
{ |
@@ -1,9 +1,8 @@ | |||
#include "treppe.h" | |||
/* | |||
dimm_stufe | |||
- dimmt stufe (0 - 15, PCA9685 outputs) mit linearen ticks | |||
von idle bis active brightness | |||
von idle bis active pwm | |||
- return false solange gedimmt wird | |||
- return true bei nächster stufe | |||
*/ | |||
@@ -13,6 +12,7 @@ bool Treppe::dimm_stufe(uint8_t stufe) | |||
current_pwm += differenz_pwm_pro_tick; | |||
else | |||
current_pwm -= differenz_pwm_pro_tick; | |||
Serial.printf("dimm_stufe %d %f\n", stufe, current_pwm); | |||
pwmController.setChannelPWM(stufe, static_cast<uint16_t>(current_pwm)); | |||
current_tick++; | |||
@@ -21,8 +21,21 @@ bool Treppe::dimm_stufe(uint8_t stufe) | |||
return true; | |||
} | |||
/* | |||
- dimmt treppe (all PCA9685 outputs) mit linearen ticks | |||
von idle bis active brightness | |||
- return false solange gedimmt wird | |||
- return true bei ende | |||
*/ | |||
bool Treppe::dimm_treppe() | |||
{ | |||
// needs to be in state machine | |||
return true; | |||
} | |||
/* | |||
animation tick | |||
- nach dem dimmen einer stufe wird die stufe weitergezählt | |||
- abbruch am ende => anim_beendet = true; | |||
*/ | |||
@@ -68,13 +81,13 @@ void Treppe::start_animation() | |||
if (fsm_outputs.dimmrichtung == DR_AUFDIMMEN) | |||
{ | |||
start_pwm = idle_brightness; | |||
ziel_pwm = active_brightness; | |||
start_pwm = idle_pwm_internal; | |||
ziel_pwm = active_pwm; | |||
} | |||
else | |||
{ | |||
start_pwm = active_brightness; | |||
ziel_pwm = idle_brightness; | |||
start_pwm = active_pwm; | |||
ziel_pwm = idle_pwm_internal; | |||
} | |||
current_tick = 0; | |||
@@ -112,12 +125,12 @@ bool Treppe::read_sensor(int sensor) | |||
{ | |||
/* | |||
reads sensors with edge detection | |||
returns true if motion was detected | |||
returns false if no motion was detected | |||
returns false if motion was detected, but state did not change back to not detected | |||
*/ | |||
reads sensors with edge detection | |||
returns true if motion was detected | |||
returns false if no motion was detected | |||
returns false if motion was detected, but state did not change back to not detected | |||
*/ | |||
uint8_t pegel = digitalRead(sensor); | |||
static uint8_t pegel_alt[2] = {0, 0}; | |||
@@ -169,11 +182,12 @@ float Treppe::read_ldr() | |||
= 37280.00/analogRead(A0) | |||
ldr_ohm = R(LDR) | |||
E(LDR) = 79.735 * R(LDR)^-0.498 (see Excel Regression) | |||
E(LDR) = 6526.5 * R(LDR)^-2 (see Excel Regression) | |||
E(LDR) = 6526.5 / (R(LDR)^2) | |||
ldr_value = E(LDR) | |||
*/ | |||
float ldr_ohm = 37280.00 / analogRead(A0); | |||
float ldr_value = 79.735 * pow(ldr_ohm, -0.498); | |||
float ldr_value = 6526.6/(ldr_ohm*ldr_ohm); | |||
return ldr_value; | |||
} | |||
@@ -192,7 +206,7 @@ bool Treppe::check_ldr() | |||
active = 1; | |||
if (ldr > ldr_schwelle + LDR_HYS) | |||
active = 0; | |||
activate_idle_pwm(active); | |||
return active; | |||
} | |||
@@ -212,8 +226,11 @@ void Treppe::task() | |||
if (fsm_outputs.status > ST_RUHEZUSTAND) | |||
{ | |||
if (anim_beendet == true && | |||
(fsm_outputs.status == ST_AUFDIMMEN_HOCH || fsm_outputs.status == ST_ABDIMMEN_HOCH || | |||
fsm_outputs.status == ST_AUFDIMMEN_RUNTER || fsm_outputs.status == ST_ABDIMMEN_RUNTER)) | |||
(fsm_outputs.status == ST_AUFDIMMEN_HOCH || | |||
fsm_outputs.status == ST_ABDIMMEN_HOCH || | |||
fsm_outputs.status == ST_AUFDIMMEN_RUNTER || | |||
fsm_outputs.status == ST_ABDIMMEN_RUNTER) | |||
) | |||
{ | |||
start_animation(); | |||
} | |||
@@ -225,7 +242,9 @@ void Treppe::task() | |||
void Treppe::berechne_dimmer() | |||
{ | |||
ticks_pro_stufe = time_per_stair / INT_TIME; // [ms] | |||
differenz_pwm_pro_tick = (float)(active_brightness - idle_brightness) / (float)ticks_pro_stufe; | |||
differenz_pwm_pro_tick = (float)(active_pwm - idle_pwm_internal) | |||
/ (float)ticks_pro_stufe; | |||
} | |||
void Treppe::setup() | |||
@@ -237,7 +256,7 @@ void Treppe::setup() | |||
pwmController.init(PCA9685_PhaseBalancer_None); | |||
//pwmController.init(PCA9685_PhaseBalancer_Linear); | |||
pwmController.setPWMFrequency(100); | |||
pwmController.setAllChannelsPWM(idle_brightness); | |||
//pwmController.setAllChannelsPWM(idle_pwm); | |||
pinMode(A0, INPUT); | |||
pinMode(SENSOR_OBEN, INPUT); | |||
@@ -249,19 +268,46 @@ void Treppe::setup() | |||
Serial.printf("Treppe: initial parameters: stufen=%d\n", stufen); | |||
} | |||
// ################################################################################################################### | |||
// GEBUFFERT => Erst im Ruhezustand übernehmen !!!! | |||
void Treppe::set_idle_pwm(uint16_t _idle_brightness) | |||
void Treppe::set_idle_prozent(int prozent) { | |||
uint16_t new_pwm = active_pwm * prozent / 100; | |||
set_idle_pwm(new_pwm); | |||
} | |||
void Treppe::set_idle_pwm(uint16_t new_idle_pwm) | |||
{ | |||
idle_brightness = _idle_brightness; | |||
if(new_idle_pwm > active_pwm) { | |||
idle_pwm = active_pwm; | |||
} else { | |||
idle_pwm = new_idle_pwm; | |||
} | |||
Serial.printf("Treppe: idle_pwm=%d\n", idle_pwm); | |||
berechne_dimmer(); | |||
Serial.printf("Treppe: idle_brightness=%d\n", idle_brightness); | |||
activate_idle_pwm(true); | |||
} | |||
void Treppe::activate_idle_pwm(bool active) | |||
{ | |||
static uint16_t last_pwm = 0; | |||
if (fsm_outputs.status == ST_RUHEZUSTAND || fsm_outputs.status == ST_INAKTIV_LDR) | |||
{ | |||
idle_pwm_internal = idle_pwm * active; | |||
if (idle_pwm_internal != last_pwm) | |||
{ | |||
// Dimming Function for all LEDS ? | |||
berechne_dimmer(); | |||
pwmController.setAllChannelsPWM(idle_pwm_internal); | |||
last_pwm = idle_pwm_internal; | |||
} | |||
} | |||
} | |||
void Treppe::set_active_pwm(uint16_t _active_brightness) | |||
void Treppe::set_active_pwm(uint16_t _active_pwm) | |||
{ | |||
active_brightness = _active_brightness; | |||
active_pwm = _active_pwm; | |||
berechne_dimmer(); | |||
Serial.printf("Treppe: active_brightness=%d\n", active_brightness); | |||
Serial.printf("Treppe: active_pwm=%d\n", active_pwm); | |||
} | |||
void Treppe::set_time_per_stair(uint16_t _time_per_stair) | |||
{ |
@@ -5,9 +5,9 @@ | |||
// #define LDRDEBUG // comment in to override LDR measurement | |||
#define LDR_HYS 5.0 // Hysteresis for switching off FSM [lux] | |||
#define LDR_HYS 1 // Hysteresis for switching off FSM [lux] | |||
#define SENSOR_OBEN 2 | |||
#define SENSOR_OBEN 16 | |||
#define SENSOR_UNTEN 12 | |||
#define OE 14 | |||
@@ -17,10 +17,11 @@ class Treppe { | |||
private: | |||
const uint8_t stufen; | |||
uint16_t time_per_stair = 300; // dimmtime per stair [ms] | |||
uint16_t idle_brightness = 0; | |||
uint16_t active_brightness = 500; | |||
uint16_t idle_pwm = 100; | |||
uint16_t idle_pwm_internal = 0; | |||
uint16_t active_pwm = 700; | |||
uint16_t ldr_schwelle = 7; // activation value for FSM [lx] | |||
uint16_t ldr_schwelle = 2; // activation value for FSM [lx] | |||
uint16_t start_pwm = 0; | |||
uint16_t ziel_pwm = 0; | |||
@@ -32,17 +33,11 @@ private: | |||
uint16_t ticks_pro_stufe = 0; | |||
float differenz_pwm_pro_tick = 0.0; | |||
bool dimm_stufe(uint8_t stufe); | |||
void anim_tick(); | |||
void start_animation(); | |||
void berechne_dimmer(); | |||
// initialize with i2c-Address 0, use Wire Library | |||
PCA9685 pwmController; | |||
FSMTreppeModelClass FSMTreppe_Obj; | |||
FSMTreppeModelClass::ExtU_FSMTreppe_T fsm_inputs; | |||
FSMTreppeModelClass::ExtY_FSMTreppe_T fsm_outputs; | |||
void print_state_on_change(); | |||
enum fsm_status_t { | |||
ST_INAKTIV_LDR =0, | |||
ST_RUHEZUSTAND =1, | |||
@@ -62,6 +57,15 @@ private: | |||
DR_AUFDIMMEN=1 | |||
}; | |||
/* DIMM */ | |||
bool dimm_stufe(uint8_t stufe); | |||
bool dimm_treppe(); | |||
void anim_tick(); | |||
void start_animation(); | |||
void berechne_dimmer(); | |||
void print_state_on_change(); | |||
/* LDR */ | |||
bool read_sensor(int sensor); | |||
float read_ldr(); | |||
bool check_ldr(); | |||
@@ -78,7 +82,9 @@ public: | |||
void task(); // call periodically | |||
// Parameter section | |||
void set_idle_pwm(uint16_t _idle_brightness); | |||
void set_active_pwm(uint16_t _active_brightness); | |||
void set_idle_prozent(int prozent); | |||
void set_idle_pwm(uint16_t _idle_pwm); | |||
void activate_idle_pwm(bool active); | |||
void set_active_pwm(uint16_t _active_pwm); | |||
void set_time_per_stair(uint16_t _time_per_stair); | |||
}; |
@@ -28,7 +28,7 @@ const char* ssid = STASSID; | |||
const char* password = STAPSK; | |||
// port 80, root directory of server '/' | |||
HTTPServer httpServer(80, "/"); | |||
HTTPServer httpServer(80, "/", &stairs); | |||
uint32_t _t=0; | |||
#define SP_US(_str,_a) Serial.print(_str); Serial.print(" took: "); Serial.print(_a); Serial.println("us") |
@@ -16,7 +16,8 @@ data_dir = data_gz | |||
[env:hardware] | |||
platform = espressif8266 | |||
board = nodemcuv2 | |||
; board = nodemcuv2 | |||
board = huzzah | |||
framework = arduino | |||
; for pio check | |||
@@ -31,7 +32,7 @@ check_skip_packages = yes | |||
board_build.filesystem = littlefs | |||
board_build.ldscript = eagle.flash.4m1m.ld | |||
extra_scripts = pre:create_gz_files.py | |||
monitor_speed = 115200 | |||
monitor_speed = 76800 | |||
[env:serial] | |||
extends = env:hardware |