45 Commits
Author SHA1 Message Date
schmidtsi76327 ad21d73fbb changed pwm setters and httpserver call 2021-07-19 11:29:51 +02:00
bartschdo76253 42a927e383 struct for treppe parameters ->eeprom 2021-07-19 11:08:13 +02:00
bartschdo76253 13db3da082 checked virtual "EEPROM" -> works 2021-07-16 21:40:51 +02:00
schmidtsi76327 9518c06fd9 format change 2021-07-11 01:45:00 +02:00
schmidtsi76327 2820869e14 some formating, add variadic templ for logf() 2021-07-10 04:12:50 +02:00
schmidtsi76327 6e810fad59 added matlab slx model 2021-07-09 13:39:07 +02:00
bartschdo76253 79a9eecaad doku details 2021-07-08 10:43:04 +02:00
schmidtsi76327 1189b7c3a4 doku.md create TODO-List 2021-07-08 03:01:10 +02:00
schmidtsi76327 7643961ed2 got dimming working, dimming from ldr, can be testet via webbrowser; dynamic dimmer_t used for both dimmers, can be selected via dimmer_type_t (DIM_STUFEN, DIM_LDR) 2021-07-08 02:54:08 +02:00
schmidtsi76327 6cc52dc460 add ifdef DEBUG_TIMING for fiming measurments 2021-07-07 21:27:07 +02:00
schmidtsi76327 d3ed19e639 add structs to treppe to clear understanding 2021-07-07 21:13:58 +02:00
schmidtsi76327 d55da4e6d7 der linker dieser sack, double declatartion of FSM, FSM3.0 implemented ! 2021-07-07 20:52:20 +02:00
schmidtsi76327 f677f18681 corrected double in FSM2, debug in treppe.cpp ! 2021-07-07 19:33:20 +02:00
schmidtsi76327 f027478e2e FSM 3.0 2021-07-07 18:28:38 +02:00
schmidtsi76327 5986beb10c add FSM3.0 src code not impl yet, add header guards and format main 2021-07-07 18:28:05 +02:00
Pupsmuckel f57e875a17 HTML Änderung 2021-07-07 17:13:40 +02:00
Pupsmuckel d16f3823b8 HTML Änderung 2021-07-07 17:08:26 +02:00
Pupsmuckel a5ac7d358b puu 2021-07-07 16:58:27 +02:00
bartschdo76253 0cd46a3c9f wrong ldr lux-calc (see Excel sheet, mixed x y ) 2021-07-06 14:19:35 +02:00
schmidtsi76327 3a93b8a002 changed static var in activate 2021-07-06 01:06:46 +02:00
schmidtsi76327 0e5085c008 small updates to treppe 2021-07-05 21:33:08 +02:00
schmidtsi76327 7177472ea6 small updates to treppe 2021-07-05 21:32:37 +02:00
schmidtsi76327 03d0cfedd1 small updates to treppe 2021-07-05 21:20:00 +02:00
schmidtsi76327 66d220cdb0 can set idle_pwm from webserver, but not working properly 2021-07-05 19:51:55 +02:00
schmidtsi76327 2754bd5247 update webserver html,js,css 2021-07-05 18:15:57 +02:00
bartschdo76253 f62a18fe66 re-addded idle_bright_internal 2021-07-05 16:59:22 +02:00
bartschdo76253 2139ff5943 Merge branch 'master' of https://git.efi.th-nuernberg.de/gitea/schmidtsi76327/ESP8266_Treppenlicht 2021-07-05 16:57:11 +02:00
bartschdo76253 6a04a4d1c9 improved activate_idle 2021-07-05 16:57:09 +02:00
schmidtsi76327 630250da78 Merge branch 'master' of https://git.efi.th-nuernberg.de/gitea/schmidtsi76327/ESP8266_Treppenlicht 2021-07-05 16:16:43 +02:00
schmidtsi76327 35ba3e7573 updates format style 2021-07-05 16:15:47 +02:00
bartschdo76253 53efb0c309 Merge branch 'master' of https://git.efi.th-nuernberg.de/gitea/schmidtsi76327/ESP8266_Treppenlicht 2021-07-05 15:56:19 +02:00
bartschdo76253 c1e24d633b activate / inactivate idle brightess w LDR 2021-07-05 15:54:35 +02:00
schmidtsi76327 5e36ef55df format 2021-07-05 15:16:43 +02:00
schmidtsi76327 6b5cabb1f4 repo PCA9685 lib 2021-07-05 14:54:23 +02:00
bartschdo76253 37380cbebc xlsx for ldr regression doku 2021-07-05 11:51:25 +02:00
bartschdo76253 8c507083a7 bugfixes 2021-07-05 11:48:31 +02:00
bartschdo76253 2f6502ce20 added LDR evaluation + sensor edge detection 2021-07-05 11:40:45 +02:00
bartschdo76253 278179fa6e doku issues 2021-07-05 10:00:21 +02:00
bartschdo76253 f38ef0ed0e Testing, Doku, Issues 2021-07-05 09:57:56 +02:00
schmidtsi76327 f2a9ed2888 clangtidy cleanups and added checks to platformio.ini 2021-07-04 14:45:14 +02:00
schmidtsi76327 1662079547 INT_TIME define added 2021-07-03 21:11:32 +02:00
schmidtsi76327 1e8d24dc40 FSM mostly working, need to implement bufferd param changes 2021-07-03 21:04:24 +02:00
schmidtsi76327 af40298378 somehow working, starting to refactor 2021-07-03 18:10:30 +02:00
schmidtsi76327 8351a6430c forgot smtn in print, spaces to 4 2021-07-03 17:51:14 +02:00
schmidtsi76327 b2ddc978b6 copy pasta :| 2021-07-03 17:46:31 +02:00
19 changed files with 796 additions and 558 deletions

No files matched your search

Binary file not shown.

Before

Width:  |  Height:  |  Size: 209 KiB

+27 -44
View File
@@ -3,63 +3,46 @@
<head> <head>
<title>ESP8266 Treppenlicht</title> <title>ESP8266 Treppenlicht</title>
<!-- main style sheet -->
<link href="/favicon.png" rel="icon" type="image/png" sizes="10x10"> <link href="/favicon.png" rel="icon" type="image/png" sizes="10x10">
<link href="/style.css" rel="stylesheet" type="text/css"> <link href="/style.css" rel="stylesheet" type="text/css">
</head> </head>
<body> <body>
<div class="kopfzeile" style="text-align: center;"> <div class="topbar">Treppenlicht</div>
<b>Treppenlicht</b>
<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="range_act_pwm" min="0" max="100" value="50">
</div>
</div> </div>
<div class="ueberschrift">
Helligkeit <div class="param_block">
<!--<label id="label_pwm"> Idle Brightness: <output id="out_idl_pwm" class="val_range">50</output> %
</label>--> <div class="slider">
<div class="slider"> <input type="range" class="regler" id="range_idl_pwm" min="0" max="100" value="50">
<input type="range" class="regler" id="helligkeit" name="rangeInput" min="0" max="100" value="50" </div>
oninput="amount1.value=helligkeit.value">
<br>
<output name="amount1" id="amount1" for="helligkeit">50</output>
</div>
</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>
</div> </div>
<div class="ueberschrift"> <div class="param_block">
Laufgeschwindigkeit Time per stair: <output id="out_tim_sta" class="val_range">50</output> %
<!--<label id="label_geschwindigkeit">
</label>--> <div class="slider">
<div class="slider"> <input type="range" class="regler" id="range_tim_sta" min="0" max="100" value="50">
<input type="range" class="regler" id="geschwindigkeit" name="rangeInput" min="0" max="100" value="50" </div>
oninput="amount3.value=geschwindigkeit.value">
<br>
<output name="amount3" id="amount3" for="geschwindigkeit">50</output>
</div>
</div> </div>
<div class="ueberschrift"> <div class="param_block">
Licht-An-Zeit On Time: <output id="out_tim_on" class="val_range">50</output> %
<!-- <label id="label_time"> <div class="slider">
</label>--> <input type="range" class="regler" id="range_tim_on" min="0" max="100" value="50">
<div class="slider"> </div>
<input type="range" class="regler" id="time" name="rangeInput" min="0" max="100" value="50"
oninput="amount4.value=time.value">
<br>
<output name="amount4" id="amount4" for="time">50</output>
</div>
</div> </div>
<div class="terminal"> <div class="terminal">
<input type="button" id="clear_term" value="clear" onclick="clearTerminal();"> <input type="button" id="clear_term" value="clear" onclick="clearTerminal();">
<input type="checkbox" id="scroll" name="scroll" value="scroll" checked> <input type="checkbox" id="scroll" name="scroll" value="scroll" checked>
+51 -12
View File
@@ -1,12 +1,54 @@
// var slider = document.getElementById("helligkeit"); let rangeValues = {};
// var output = document.getElementById("l_pwm"); let xhrUpd = new XMLHttpRequest();
// output.innerHTML = slider.value; // Display the default slider value
// // Update the current slider value (each time you drag the slider handle) xhrUpd.onreadystatechange = function(){
// slider.oninput = function() { if(xhrUpd.readyState == 4) {
// output.innerHTML = this.value; 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(); let xhr = new XMLHttpRequest();
@@ -26,15 +68,12 @@ xhr.onreadystatechange = function(){
} }
} }
} }
function reloadTerminal() { function reloadTerminal() {
xhr.open("POST", "/app=terminal", true); xhr.open("POST", "/terminal", true);
xhr.send(); xhr.send();
setTimeout(reloadTerminal, 1000); setTimeout(reloadTerminal, 1000);
}; };
reloadTerminal(); reloadTerminal();
function clearTerminal() { function clearTerminal() {
document.getElementById("term").innerHTML = ''; document.getElementById("term").innerHTML = '';
} }
+40 -32
View File
@@ -1,45 +1,44 @@
html { html {
font-size: 16px; font-size: 16px;
font-family: sans-serif, Arial, Helvetica; font-family: sans-serif, Arial, Helvetica;
background-color: #d4d4d4; background-color: #ffffff;
height: 100%; height: 100%;
/* background-image: url('Background.png'); */
background-repeat: repeat;
background-size: 150% 150%;
} }
body { body {
height: 100%; height: 100%;
margin: 0 auto;
border: none;
border-radius: 3; border-radius: 3;
} }
.topbar { .topbar {
padding: 1em; padding: 10px;
background-color: #1f1f1f; background-color: #585858;
color: white; color: white;
font-size: x-large; font-size: xx-large;
text-align: center; text-align: center;
} }
.ueberschrift{ .param_block{
color: #ffffff; padding: 1em;
font-size: 50px; color: #000000;
width: 100%; border: 1px solid darkred;
text-align: center; font-size: x-large;
width: 80%;
}
.val_range {
font-weight: bold;
} }
.regler{ .regler{
/* -webkit-appearance: none; */
-webkit-appearance: none; height: 50px;
height: 30px;
width: 100%; width: 100%;
border-radius: 20px; border-radius: 20px;
outline: black; outline: black;
background-color: rgb(176, 188, 228); background-color: rgb(176, 188, 228);
} }
.regler::-webkit-slider-thumb{ /* .regler::-webkit-slider-thumb{
-webkit-appearance: none; -webkit-appearance: none;
appearance: none; appearance: none;
width: 5%; width: 5%;
@@ -47,29 +46,21 @@ body {
border-radius: 10px; border-radius: 10px;
background-color: rgb(107, 122, 192); background-color: rgb(107, 122, 192);
cursor:pointer; cursor:pointer;
} } */
input[type=range]::-webkit-slider-thumb{ /* input[type=range]::-webkit-slider-thumb{
-webkit-appearance: none; -webkit-appearance: none;
border:none; border:none;
height: 30px; height: 30px;
width: 4%; width: 4%;
border-radius: 30px; border-radius: 30px;
} } */
.slider {
width: 100%;
}
.kopfzeile{ .slider {
color: #1f1f1f; margin: 1%;
font-size: 50px;
width: 100%;
background-color: #8d8a8a;
} }
/*-------------------------------------------------------*/ /*-------------------------------------------------------*/
/*Switch: /*Switch:
.switch { .switch {
position: relative; position: relative;
@@ -119,4 +110,21 @@ input:checked + .slider:before {
#clear_term { #clear_term {
margin: 2px; margin: 2px;
} }
input[type="number"] {
width: 100px;
}
input:invalid+span:after {
content: '✖';
padding-left: 5px;
}
input:valid+span:after {
content: '✓';
padding-left: 5px;
}
+45 -2
View File
@@ -54,14 +54,27 @@ else
server.streamFile(f, mime::getContentType(SRH::_path), requestMethod); server.streamFile(f, mime::getContentType(SRH::_path), requestMethod);
``` ```
LED_sequence_v1: ### HW issues
- GPIO2 used as input -> must be high during startup
- PCB Solution: cut trace to GPIO2, solder bridge to GPIO16
- -> disadvantage: GPIO16 is not interrupt capable
### FSM 2 - to do
- stairway light switches off after timeout
- switches concurrently on again if sensor is still high
- desired behavior? Defective Sensor would cause continuos animation
- edge detection / interrupts as solution ?
### LED_sequence_v1:
TODO: TODO:
- disable led stripes after defined time (webserver paramter?) - disable led stripes after defined time (webserver paramter?)
- define what to do if people enter stairs from different directions - define what to do if people enter stairs from different directions
- CAUTION: Sensor-Deadtime at LEAST 8 seconds - CAUTION: Sensor-Deadtime at LEAST 8 seconds
- --> switch off with person leaving stairs might not be possible - --> switch off with person leaving stairs might not be possible
Webserver on v0.3.0 now working with LittleFS ### Webserver on v0.3.0 now working with LittleFS
TODO: TODO:
- check dir for files automatic - check dir for files automatic
- move handleNotFound to httpserver.h - move handleNotFound to httpserver.h
@@ -84,3 +97,33 @@ new easier script needed to just convert to .gz
maybe measure timings on ESP maybe measure timings on ESP
__=> use serveStatic because way simpler !__ __=> use serveStatic because way simpler !__
__=> serverStatic("/") works wonders__
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARHRRHRGH
Two implementations of FSM are not that good,
linker puts them together ?!?
:):):):):):):)
=> maybe investigate for doc
### TODO Treppe
- dynamic lighting with ldr
- http control over active pwm ... => set_active_pwm()
- testing if dimming crashes when two animations
-> ldr does not interrupt animation, animation get's finished and stairs fade out -> FSM works without collisions
- interrupt to pending from sensors
- settings struct
- script for gdb on windows
- dynamic time for dimming => set_time_per_stair()
- welcome animation ?
- on/off switch http
- use logging to serial http monitor with httpserver.logt();
- behavior when someone enters stairway from opposite direction while animation is running?
-> currently ignored, second persons walks in darkness
-> animation from both sides?
-> problem: person 1 leaving stairway might pass the sensor right after person 2 -> person 1 leaving not detected
- behavior when someone enters stairway from opposite direction after animation finished but person 1 is still on stairway?
-> currently stairs fade off from direction 1
-> additional wait-state between "warten hoch/runter" and "abdimmen hoch/runter" after sensor detected person?
+6 -3
View File
@@ -1,8 +1,9 @@
#pragma once #ifndef __OTA_H
#define __OTA_H
#include <ArduinoOTA.h>
#include <ESP8266WiFi.h> #include <ESP8266WiFi.h>
#include <WiFiUdp.h> #include <WiFiUdp.h>
#include <ArduinoOTA.h>
void ota_setup() { void ota_setup() {
ArduinoOTA.setPort(8266); ArduinoOTA.setPort(8266);
@@ -45,4 +46,6 @@ void ota_setup() {
}); });
ArduinoOTA.begin(); ArduinoOTA.begin();
} }
#endif // __OTA_H
+3 -7
View File
@@ -2,7 +2,7 @@
FSInfo fsinfo; FSInfo fsinfo;
bool mount_fs() { auto mount_fs() -> bool {
if(!LittleFS.begin()) { if(!LittleFS.begin()) {
Serial.println("[ERROR] LittleFS.info(), reset ..."); Serial.println("[ERROR] LittleFS.info(), reset ...");
return false; return false;
@@ -25,7 +25,7 @@ bool mount_fs() {
return true; return true;
} }
bool format_fs() { auto format_fs() -> bool {
printf("Formatting FS ! \n\r"); printf("Formatting FS ! \n\r");
return LittleFS.format(); return LittleFS.format();
} }
@@ -121,8 +121,4 @@ void deleteFile(const char * path) {
} else { } else {
Serial.println("Delete failed"); Serial.println("Delete failed");
} }
} }
-1
View File
@@ -3,7 +3,6 @@
#include <LittleFS.h> #include <LittleFS.h>
// some usefull wrappers for Filesystem // some usefull wrappers for Filesystem
bool mount_fs(); bool mount_fs();
bool format_fs(); bool format_fs();
+79 -58
View File
@@ -1,68 +1,89 @@
#include "httpserver.h" #include "httpserver.h"
auto HTTPServer::start() -> bool {
if (!mount_fs()) {
logf("cant mount filesystem, EXIT !\n\r");
return false;
}
bool HTTPServer::start() { logf("LittleFS mounted !\n\r");
if(!mount_fs()) { logf("root:\n\r");
logf("cant mount filesystem, EXIT !\n\r"); this->listRoot();
return false; logf("\n\r");
// default handler
this->onNotFound([this]() {
String message = "File Not Found\n\n";
message += "URI: ";
message += uri();
message += "\nMethod: ";
message += (method() == HTTP_GET) ? "GET" : "POST";
message += "\nArguments: ";
message += args();
message += "\n";
for (uint8_t i = 0; i < args(); i++) {
message += " " + argName(i) + ": " + arg(i) + "\n";
} }
logf("LittleFS mounted !\n\r"); send(404, "text/plain", message);
logf("root:\n\r"); });
this->listRoot();
logf("\n\r");
// default handler // add static root file handler for http
this->onNotFound([this]() { this->serveStatic("/", LittleFS, "/");
String message = "File Not Found\n\n"; this->begin();
message += "URI: "; Serial.printf("Server active on Port 80 !\n\r");
message += uri(); return true;
message += "\nMethod: ";
message += (method() == HTTP_GET) ? "GET" : "POST";
message += "\nArguments: ";
message += args();
message += "\n";
for (uint8_t i = 0; i < args(); i++) {
message += " " + argName(i) + ": " + arg(i) + "\n";
}
send(404, "text/plain", message);
});
// add static root file handler for http
this->serveStatic("/", LittleFS, "/");
this->begin();
Serial.printf("Server active on Port 80 !\n\r");
return true;
}
void HTTPServer::logf(const char *format, ...) {
va_list args;
va_start(args, format);
char temp[64];
size_t len = vsnprintf(temp, sizeof(temp), format, args);
Serial.print(log_prefix);
Serial.write(temp, len);
va_end(args);
}
void HTTPServer::logt(const char *format, ...) {
va_list args;
va_start(args, format);
// append logging string to local buffer
if(tbuf_head < TBUF_LEN) {
size_t len = vsnprintf(tbuf+tbuf_head, TBUF_LEN-tbuf_head, format, args);
tbuf_head += len;
}
va_end(args);
} }
void HTTPServer::start_apps() { void HTTPServer::start_apps() {
// application handler // application handler
this->on("/app=terminal", HTTP_POST, [this]() {
if(tbuf_head) {
send(200, "text/plain", tbuf);
tbuf_head = 0;
}
});
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_act_pwm")) {
treppe->set_active_pwm(arg(i).toInt(), VORGABE_PROZENT);
}
else if (argName(i).equals("range_idl_pwm")) {
treppe->set_idle_pwm_max(arg(i).toInt(), VORGABE_PROZENT);
}
else if (argName(i).equals("range_tim_sta")) {
}
else if (argName(i).equals("range_tim_on")) {
}
}
}
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", "");
}
});
}
template <class... Args>
void HTTPServer::logf(const char *format, Args... args) const {
Serial.print(log_prefix);
Serial.printf(format, args...);
}
void HTTPServer::logt(const char *format, ...) {
va_list args;
va_start(args, format);
// append logging string to local buffer
if (tbuf_head < TBUF_LEN) {
tbuf_head +=
vsnprintf(tbuf + tbuf_head, TBUF_LEN - tbuf_head, format, args);
}
va_end(args);
} }
+23 -25
View File
@@ -1,42 +1,40 @@
#ifndef __HTTPSERVER_H
#define __HTTPSERVER_H
// Wrapper for ESP8266WebServer with Filesystem as HTTP source // Wrapper for ESP8266WebServer with Filesystem as HTTP source
#pragma once #include "filesys.h"
#include "treppe.h"
#include <ESP8266WebServer.h> #include <ESP8266WebServer.h>
#include <stdarg.h> #include <stdarg.h>
#include "filesys.h"
// debug log <ESP8266WebServer.h> // debug log <ESP8266WebServer.h>
// #define DEBUGV(f,...) do { Serial.printf(PSTR(f), ##__VA_ARGS__); } while (0) // #define DEBUGV(f,...) do { Serial.printf(PSTR(f), ##__VA_ARGS__); } while (0)
#define TBUF_LEN 256 #define TBUF_LEN 256
class HTTPServer : public ESP8266WebServer { class HTTPServer : public ESP8266WebServer {
private: private:
const char* rootDir = "/"; const char *rootDir = "/";
const char* log_prefix = "[HTTPServer] "; const char *log_prefix = "[HTTPServer] ";
size_t tbuf_head = 0; size_t tbuf_head = 0;
char tbuf[TBUF_LEN]; char tbuf[TBUF_LEN];
void listRoot() { void listRoot() { ls(rootDir); }
ls(rootDir); Treppe *treppe;
}
public: public:
HTTPServer(const int _port, const char* _rootDir) : HTTPServer(const int _port, const char *_rootDir, Treppe *_treppe)
ESP8266WebServer(_port), rootDir(_rootDir) : ESP8266WebServer(_port), rootDir(_rootDir), treppe(_treppe) {}
{ } ~HTTPServer() { Serial.printf("[HTTPServer] shut down ...\n\r"); }
~HTTPServer()
{ bool start();
Serial.printf("[HTTPServer] shut down ...\n\r"); void start_apps();
}
template <class... Args>
bool start(); void logf(const char *format, Args... args) const;
void start_apps(); void logt(const char *format, ...);
void logf(const char *format, ...);
void logt(const char *format, ...);
}; };
#endif // __HTTPSERVER_H
@@ -7,27 +7,28 @@
// //
// Code generated for Simulink model 'FSMTreppe'. // Code generated for Simulink model 'FSMTreppe'.
// //
// Model version : 1.29 // Model version : 1.51
// Simulink Coder version : 9.5 (R2021a) 14-Nov-2020 // Simulink Coder version : 9.5 (R2021a) 14-Nov-2020
// C/C++ source code generated on : Sat Jul 3 17:39:25 2021 // C/C++ source code generated on : Wed Jul 7 18:54:01 2021
// //
// Target selection: ert.tlc // Target selection: ert.tlc
// Embedded hardware selection: ARM Compatible->ARM Cortex-M // Embedded hardware selection: ARM Compatible->ARM Cortex-M
// Code generation objectives: Unspecified // Code generation objectives: Unspecified
// Validation result: Not run // Validation result: Not run
// //
#include "FSMTreppe2.h" #include "FSMTreppe3.h"
#include <stdint.h>
// Named constants for Chart: '<Root>/FSMTreppe' // Named constants for Chart: '<Root>/FSMTreppe'
const uint8_t FSMTreppe_IN_abdimmen_hoch = 1U; const uint32_t FSMTreppe_IN_abdimmen_hoch = 1U;
const uint8_t FSMTreppe_IN_abdimmen_runter = 2U; const uint32_t FSMTreppe_IN_abdimmen_ldr = 2U;
const uint8_t FSMTreppe_IN_aufdimmen_hoch = 3U; const uint32_t FSMTreppe_IN_abdimmen_runter = 3U;
const uint8_t FSMTreppe_IN_aufdimmen_runter = 4U; const uint32_t FSMTreppe_IN_aufdimmen_hoch = 4U;
const uint8_t FSMTreppe_IN_inaktiv = 5U; const uint32_t FSMTreppe_IN_aufdimmen_ldr = 5U;
const uint8_t FSMTreppe_IN_ruhezustand = 6U; const uint32_t FSMTreppe_IN_aufdimmen_runter = 6U;
const uint8_t FSMTreppe_IN_warten_hoch = 7U; const uint32_t FSMTreppe_IN_inaktiv = 7U;
const uint8_t FSMTreppe_IN_warten_runter = 8U; const uint32_t FSMTreppe_IN_ruhezustand = 8U;
const uint32_t FSMTreppe_IN_warten_hoch = 9U;
const uint32_t FSMTreppe_IN_warten_runter = 10U;
// Model step function // Model step function
void FSMTreppeModelClass::step() void FSMTreppeModelClass::step()
@@ -56,13 +57,28 @@ void FSMTreppeModelClass::step()
FSMTreppe_Y.dimmrichtung = 0U; FSMTreppe_Y.dimmrichtung = 0U;
// Outport: '<Root>/status' // Outport: '<Root>/status'
FSMTreppe_Y.status = 4U; FSMTreppe_Y.status = 6U;
if (FSMTreppe_U.anim_beendet || (FSMTreppe_DW.temporalCounter_i1 >= 500U)) if ((FSMTreppe_U.anim_beendet == 1U) || (FSMTreppe_DW.temporalCounter_i1 >=
{ 500U)) {
FSMTreppe_DW.is_c3_FSMTreppe = FSMTreppe_IN_ruhezustand; FSMTreppe_DW.is_c3_FSMTreppe = FSMTreppe_IN_ruhezustand;
// Outport: '<Root>/status' // Outport: '<Root>/status'
FSMTreppe_Y.status = 1U; FSMTreppe_Y.status = 3U;
}
break;
case FSMTreppe_IN_abdimmen_ldr:
// Outport: '<Root>/status'
FSMTreppe_Y.status = 2U;
// Outport: '<Root>/dimmrichtung'
FSMTreppe_Y.dimmrichtung = 0U;
if ((FSMTreppe_U.anim_beendet == 1U) || (FSMTreppe_DW.temporalCounter_i1 >=
500U)) {
FSMTreppe_DW.is_c3_FSMTreppe = FSMTreppe_IN_inaktiv;
// Outport: '<Root>/status'
FSMTreppe_Y.status = 0U;
} }
break; break;
@@ -71,13 +87,13 @@ void FSMTreppeModelClass::step()
FSMTreppe_Y.dimmrichtung = 0U; FSMTreppe_Y.dimmrichtung = 0U;
// Outport: '<Root>/status' // Outport: '<Root>/status'
FSMTreppe_Y.status = 7U; FSMTreppe_Y.status = 9U;
if (FSMTreppe_U.anim_beendet || (FSMTreppe_DW.temporalCounter_i1 >= 500U)) if ((FSMTreppe_U.anim_beendet == 1U) || (FSMTreppe_DW.temporalCounter_i1 >=
{ 500U)) {
FSMTreppe_DW.is_c3_FSMTreppe = FSMTreppe_IN_ruhezustand; FSMTreppe_DW.is_c3_FSMTreppe = FSMTreppe_IN_ruhezustand;
// Outport: '<Root>/status' // Outport: '<Root>/status'
FSMTreppe_Y.status = 1U; FSMTreppe_Y.status = 3U;
} }
break; break;
@@ -89,12 +105,27 @@ void FSMTreppeModelClass::step()
FSMTreppe_Y.dimmrichtung = 1U; FSMTreppe_Y.dimmrichtung = 1U;
// Outport: '<Root>/status' // Outport: '<Root>/status'
FSMTreppe_Y.status = 2U; FSMTreppe_Y.status = 4U;
if (FSMTreppe_U.anim_beendet || (FSMTreppe_DW.temporalCounter_i1 >= 500U)) if ((FSMTreppe_U.anim_beendet == 1U) || (FSMTreppe_DW.temporalCounter_i1 >=
{ 500U)) {
FSMTreppe_DW.is_c3_FSMTreppe = FSMTreppe_IN_warten_hoch; FSMTreppe_DW.is_c3_FSMTreppe = FSMTreppe_IN_warten_hoch;
FSMTreppe_DW.temporalCounter_i1 = 0U; FSMTreppe_DW.temporalCounter_i1 = 0U;
// Outport: '<Root>/status'
FSMTreppe_Y.status = 5U;
}
break;
case FSMTreppe_IN_aufdimmen_ldr:
// Outport: '<Root>/status'
FSMTreppe_Y.status = 1U;
// Outport: '<Root>/dimmrichtung'
FSMTreppe_Y.dimmrichtung = 1U;
if ((FSMTreppe_U.anim_beendet == 1U) || (FSMTreppe_DW.temporalCounter_i1 >=
500U)) {
FSMTreppe_DW.is_c3_FSMTreppe = FSMTreppe_IN_ruhezustand;
// Outport: '<Root>/status' // Outport: '<Root>/status'
FSMTreppe_Y.status = 3U; FSMTreppe_Y.status = 3U;
} }
@@ -108,32 +139,36 @@ void FSMTreppeModelClass::step()
FSMTreppe_Y.dimmrichtung = 1U; FSMTreppe_Y.dimmrichtung = 1U;
// Outport: '<Root>/status' // Outport: '<Root>/status'
FSMTreppe_Y.status = 5U; FSMTreppe_Y.status = 7U;
if (FSMTreppe_U.anim_beendet || (FSMTreppe_DW.temporalCounter_i1 >= 500U)) if ((FSMTreppe_U.anim_beendet == 1U) || (FSMTreppe_DW.temporalCounter_i1 >=
{ 500U)) {
FSMTreppe_DW.is_c3_FSMTreppe = FSMTreppe_IN_warten_runter; FSMTreppe_DW.is_c3_FSMTreppe = FSMTreppe_IN_warten_runter;
FSMTreppe_DW.temporalCounter_i1 = 0U; FSMTreppe_DW.temporalCounter_i1 = 0U;
// Outport: '<Root>/status' // Outport: '<Root>/status'
FSMTreppe_Y.status = 6U; FSMTreppe_Y.status = 8U;
} }
break; break;
case FSMTreppe_IN_inaktiv: case FSMTreppe_IN_inaktiv:
// Outport: '<Root>/status' // Outport: '<Root>/status'
FSMTreppe_Y.status = 0U; FSMTreppe_Y.status = 0U;
if (FSMTreppe_U.ldr_schwelle == 1.0) { if (FSMTreppe_U.ldr_schwelle == 1U) {
FSMTreppe_DW.is_c3_FSMTreppe = FSMTreppe_IN_ruhezustand; FSMTreppe_DW.is_c3_FSMTreppe = FSMTreppe_IN_aufdimmen_ldr;
FSMTreppe_DW.temporalCounter_i1 = 0U;
// Outport: '<Root>/status' // Outport: '<Root>/status'
FSMTreppe_Y.status = 1U; FSMTreppe_Y.status = 1U;
// Outport: '<Root>/dimmrichtung'
FSMTreppe_Y.dimmrichtung = 1U;
} }
break; break;
case FSMTreppe_IN_ruhezustand: case FSMTreppe_IN_ruhezustand:
// Outport: '<Root>/status' // Outport: '<Root>/status'
FSMTreppe_Y.status = 1U; FSMTreppe_Y.status = 3U;
if (FSMTreppe_U.sensor_unten) { if (FSMTreppe_U.sensor_unten == 1U) {
FSMTreppe_DW.is_c3_FSMTreppe = FSMTreppe_IN_aufdimmen_hoch; FSMTreppe_DW.is_c3_FSMTreppe = FSMTreppe_IN_aufdimmen_hoch;
FSMTreppe_DW.temporalCounter_i1 = 0U; FSMTreppe_DW.temporalCounter_i1 = 0U;
@@ -144,8 +179,8 @@ void FSMTreppeModelClass::step()
FSMTreppe_Y.dimmrichtung = 1U; FSMTreppe_Y.dimmrichtung = 1U;
// Outport: '<Root>/status' // Outport: '<Root>/status'
FSMTreppe_Y.status = 2U; FSMTreppe_Y.status = 4U;
} else if (FSMTreppe_U.sensor_oben) { } else if (FSMTreppe_U.sensor_oben == 1U) {
FSMTreppe_DW.is_c3_FSMTreppe = FSMTreppe_IN_aufdimmen_runter; FSMTreppe_DW.is_c3_FSMTreppe = FSMTreppe_IN_aufdimmen_runter;
FSMTreppe_DW.temporalCounter_i1 = 0U; FSMTreppe_DW.temporalCounter_i1 = 0U;
@@ -156,20 +191,24 @@ void FSMTreppeModelClass::step()
FSMTreppe_Y.dimmrichtung = 1U; FSMTreppe_Y.dimmrichtung = 1U;
// Outport: '<Root>/status' // Outport: '<Root>/status'
FSMTreppe_Y.status = 5U; FSMTreppe_Y.status = 7U;
} else if (FSMTreppe_U.ldr_schwelle == 0.0) { } else if (FSMTreppe_U.ldr_schwelle == 0U) {
FSMTreppe_DW.is_c3_FSMTreppe = FSMTreppe_IN_inaktiv; FSMTreppe_DW.is_c3_FSMTreppe = FSMTreppe_IN_abdimmen_ldr;
FSMTreppe_DW.temporalCounter_i1 = 0U;
// Outport: '<Root>/status' // Outport: '<Root>/status'
FSMTreppe_Y.status = 0U; FSMTreppe_Y.status = 2U;
// Outport: '<Root>/dimmrichtung'
FSMTreppe_Y.dimmrichtung = 0U;
} }
break; break;
case FSMTreppe_IN_warten_hoch: case FSMTreppe_IN_warten_hoch:
// Outport: '<Root>/status' // Outport: '<Root>/status'
FSMTreppe_Y.status = 3U; FSMTreppe_Y.status = 5U;
if (FSMTreppe_U.sensor_oben || (FSMTreppe_DW.temporalCounter_i1 >= 500U)) if ((FSMTreppe_U.sensor_oben == 1U) || (FSMTreppe_DW.temporalCounter_i1 >=
{ 500U)) {
FSMTreppe_DW.is_c3_FSMTreppe = FSMTreppe_IN_abdimmen_hoch; FSMTreppe_DW.is_c3_FSMTreppe = FSMTreppe_IN_abdimmen_hoch;
FSMTreppe_DW.temporalCounter_i1 = 0U; FSMTreppe_DW.temporalCounter_i1 = 0U;
@@ -177,16 +216,16 @@ void FSMTreppeModelClass::step()
FSMTreppe_Y.dimmrichtung = 0U; FSMTreppe_Y.dimmrichtung = 0U;
// Outport: '<Root>/status' // Outport: '<Root>/status'
FSMTreppe_Y.status = 4U; FSMTreppe_Y.status = 6U;
} }
break; break;
default: default:
// Outport: '<Root>/status' // Outport: '<Root>/status'
// case IN_warten_runter: // case IN_warten_runter:
FSMTreppe_Y.status = 6U; FSMTreppe_Y.status = 8U;
if (FSMTreppe_U.sensor_unten || (FSMTreppe_DW.temporalCounter_i1 >= 500U)) if ((FSMTreppe_U.sensor_unten == 1U) || (FSMTreppe_DW.temporalCounter_i1 >=
{ 500U)) {
FSMTreppe_DW.is_c3_FSMTreppe = FSMTreppe_IN_abdimmen_runter; FSMTreppe_DW.is_c3_FSMTreppe = FSMTreppe_IN_abdimmen_runter;
FSMTreppe_DW.temporalCounter_i1 = 0U; FSMTreppe_DW.temporalCounter_i1 = 0U;
@@ -194,7 +233,7 @@ void FSMTreppeModelClass::step()
FSMTreppe_Y.dimmrichtung = 0U; FSMTreppe_Y.dimmrichtung = 0U;
// Outport: '<Root>/status' // Outport: '<Root>/status'
FSMTreppe_Y.status = 7U; FSMTreppe_Y.status = 9U;
} }
break; break;
} }
@@ -7,9 +7,9 @@
// //
// Code generated for Simulink model 'FSMTreppe'. // Code generated for Simulink model 'FSMTreppe'.
// //
// Model version : 1.28 // Model version : 1.51
// Simulink Coder version : 9.5 (R2021a) 14-Nov-2020 // Simulink Coder version : 9.5 (R2021a) 14-Nov-2020
// C/C++ source code generated on : Sat Jul 3 13:50:17 2021 // C/C++ source code generated on : Wed Jul 7 18:54:01 2021
// //
// Target selection: ert.tlc // Target selection: ert.tlc
// Embedded hardware selection: ARM Compatible->ARM Cortex-M // Embedded hardware selection: ARM Compatible->ARM Cortex-M
@@ -27,24 +27,24 @@ class FSMTreppeModelClass {
public: public:
// Block states (default storage) for system '<Root>' // Block states (default storage) for system '<Root>'
struct DW_FSMTreppe_T { struct DW_FSMTreppe_T {
uint16_t temporalCounter_i1; // '<Root>/FSMTreppe' uint16_t temporalCounter_i1=0; // '<Root>/FSMTreppe'
uint8_t is_active_c3_FSMTreppe; // '<Root>/FSMTreppe' uint8_t is_active_c3_FSMTreppe=0; // '<Root>/FSMTreppe'
uint8_t is_c3_FSMTreppe; // '<Root>/FSMTreppe' uint8_t is_c3_FSMTreppe=0; // '<Root>/FSMTreppe'
}; };
// External inputs (root inport signals with default storage) // External inputs (root inport signals with default storage)
struct ExtU_FSMTreppe_T { struct ExtU_FSMTreppe_T {
bool sensor_unten; // '<Root>/sensor_unten' uint32_t sensor_unten=0; // '<Root>/sensor_unten'
bool sensor_oben; // '<Root>/sensor_oben' uint32_t sensor_oben=0; // '<Root>/sensor_oben'
bool anim_beendet; // '<Root>/anim_beendet' uint32_t anim_beendet=0; // '<Root>/anim_beendet'
double ldr_schwelle; // '<Root>/ldr_schwelle' uint32_t ldr_schwelle=0; // '<Root>/ldr_schwelle'
}; };
// External outputs (root outports fed by signals with default storage) // External outputs (root outports fed by signals with default storage)
struct ExtY_FSMTreppe_T { struct ExtY_FSMTreppe_T {
uint8_t laufrichtung; // '<Root>/laufrichtung' uint32_t laufrichtung=0; // '<Root>/laufrichtung'
uint8_t status; // '<Root>/status' uint32_t status=0; // '<Root>/status'
uint8_t dimmrichtung; // '<Root>/dimmrichtung' uint32_t dimmrichtung=0; // '<Root>/dimmrichtung'
}; };
// model initialize function // model initialize function
@@ -67,13 +67,16 @@ class FSMTreppeModelClass {
// Root inports set method // Root inports set method
void setExternalInputs(const ExtU_FSMTreppe_T* pExtU_FSMTreppe_T) void setExternalInputs(const ExtU_FSMTreppe_T* pExtU_FSMTreppe_T)
{ {
FSMTreppe_U = *pExtU_FSMTreppe_T; FSMTreppe_U.anim_beendet = pExtU_FSMTreppe_T->anim_beendet;
FSMTreppe_U.ldr_schwelle = pExtU_FSMTreppe_T->ldr_schwelle;
FSMTreppe_U.sensor_oben = pExtU_FSMTreppe_T->sensor_oben;
FSMTreppe_U.sensor_unten = pExtU_FSMTreppe_T->sensor_unten;
} }
// Root-level structure-based outputs get method // Root-level structure-based outputs get method
// Root outports get method // Root outports get method
const FSMTreppeModelClass::ExtY_FSMTreppe_T & getExternalOutputs() const const FSMTreppeModelClass::ExtY_FSMTreppe_T getExternalOutputs() const
{ {
return FSMTreppe_Y; return FSMTreppe_Y;
} }
Binary file not shown.
+294 -203
View File
@@ -1,242 +1,333 @@
#include "treppe.h" #include "treppe.h"
// #define DEBUG_TIMING
uint8_t Treppe::softstart_led(uint8_t led, uint16_t startval, uint16_t stopval){ /*
/* - dimmer_tick: increment pwm jeden tick, bis anim beendet
softstart task - return: fsm_pend.anim_beendet
*/
bool Treppe::dimmer_tick(dimmer_t *dimmer, bool dim_type) {
dimmer->pwm += dimmer->delta_pwm;
Serial.printf("%.0f", dimmer->pwm);
- get's called at regular intervals (1ms at the moment) if (dim_type == DIM_STUFEN) {
- dimms single led (0 - 15, PCA9685 outputs) with linear intervals vom startval to stopval pwmController.setChannelPWM(dimmer->stufe,
- calculates pwm steps depending on startval, stopval and timeinterval static_cast<uint16_t>(dimmer->pwm));
- -> results in constanst speed } else { // DIM_LDR
- returns 1 if led dimming is running pwmController.setAllChannelsPWM(static_cast<uint16_t>(dimmer->pwm));
- returns 0 if led dimming is finished }
*/ dimmer->tick++;
if (dimmer->tick < dimmer->ticks) {
Serial.print("-");
return false;
}
Serial.println("");
static uint8_t lastled = 255; if (dim_type == DIM_LDR) {
static float current_pwm = 0; Serial.printf("DIM_LDR: start: %d, ziel: %d\n", dimmer->start_pwm,
static float stepsize = 1.0; dimmer->ziel_pwm);
if(led != lastled){ return true;
pwmController.setChannelPWM(led, (uint16_t)startval); } else // DIM_STUFEN
lastled = led; {
current_pwm = startval; Serial.printf("DIM_STUFEN: stufe: %d, start: %d, ziel: %d\n",
stepsize = INT_TIME*abs(stopval - startval)/(float)time_per_stair; // only valid at 1ms function call interval dimmer->stufe, dimmer->start_pwm, dimmer->ziel_pwm);
return 1;
if (fsm_outputs.laufrichtung == LR_HOCH) {
if (dimmer->stufe >= stufen - 1)
return true;
dimmer->stufe++;
} else // LR_RUNTER
{
if (dimmer->stufe <= 0)
return true;
dimmer->stufe--;
} }
dimmer->tick = 0;
if(startval > stopval){ dimmer->pwm = dimmer->start_pwm;
current_pwm -= stepsize; }
} return false;
else {
current_pwm += stepsize;
}
// Serial.println((uint16_t)current_pwm);
pwmController.setChannelPWM(led, (uint16_t)current_pwm);
if(current_pwm > stopval - stepsize && current_pwm < stopval + stepsize){
if(stopval == 0) pwmController.setChannelPWM(led, 0);
return 0;
}
return 1;
} }
void Treppe::ledsequence(){ // startbedingunen für animation
static int8_t led = 0; void Treppe::start_animation(dimmer_t *dimmer, bool dim_type, uint16_t on_pwm,
static uint16_t brightness = 0; uint16_t off_pwm) {
static uint16_t lastbrightness = 0; fsm_pend.anim_beendet = false;
static uint16_t status = 0;
uint16_t status_build = 0;
status_build |= direction << 8;
status_build |= state;
if(status_build != status){ // check if any parameter changed
finish = 0; // set state unfinished -> start action
if(direction) led = 0; // reset led counter depending of direction
else led = stairs-1;
if(state){
brightness = active_brightness; // set brightness value depending of on/off
lastbrightness = idle_brightness;
}
else{
brightness = idle_brightness;
lastbrightness = active_brightness;
}
status = status_build; // set parameter memory
Serial.printf("----Status Changed! onoff: %d, dir: %d\n", state, direction); if (dim_type == DIM_STUFEN) {
} if (fsm_outputs.laufrichtung == LR_HOCH)
if(!finish){ // finish == 0 -> action pending dimmer->stufe = 0;
if(!softstart_led(led,lastbrightness, brightness)){ else
Serial.printf("one LED finished: led: %d, last: %d, curr %d\n", dimmer->stufe = stufen - 1;
led, lastbrightness, brightness);
if(direction){ dimmer->ticks = parameters.time_per_stair / INT_TIME; // [ms]
led++; } else { // DIM_LDR
if(led >= stairs) dimmer->ticks = parameters.time_ldr / INT_TIME; // [ms]
finish = 1;
}
else{
led--;
if(led < 0)
finish = 1;
}
}
}
}
void Treppe::rampe()
{
if(state) {
finish = 0;
state = 0;// set parameter memory
} }
if(!finish) { if (fsm_outputs.dimmrichtung == DR_AUFDIMMEN) {
if(direction) { // aufwärts dimmer->start_pwm = off_pwm;
if(tick >= ticks_treppe-1) { // ziel erreicht dimmer->ziel_pwm = on_pwm;
Serial.println("[Treppe] oberster tick !"); dimmer->delta_pwm = (float)(on_pwm - off_pwm) / (float)dimmer->ticks;
finish = 1; } else {
return; dimmer->start_pwm = on_pwm;
} dimmer->ziel_pwm = off_pwm;
tick++; // eins hoch dimmer->delta_pwm = (float)(off_pwm - on_pwm) / (float)dimmer->ticks;
}
else { // abwärts
if(tick <= 0) { // ziel erreicht
Serial.println("[Treppe] unterster tick !");
finish = 1;
return;
}
tick--; // eins runter
}
stufe = tick / ticks_pro_stufe;
float new_pwm = 0.0;
if(an_aus) {
new_pwm = differenz_pwm_pro_tick * (tick - ticks_pro_stufe*stufe);
new_pwm += idle_brightness;
if(direction) new_pwm += differenz_pwm_pro_tick;
}
else {
new_pwm = active_brightness - differenz_pwm_pro_tick * (tick - ticks_pro_stufe*stufe);
new_pwm += idle_brightness;
if(direction) new_pwm -= differenz_pwm_pro_tick;
}
pwmController.setChannelPWM(stufe, (uint16_t) new_pwm);
Serial.printf("tick %04u, led %02d:%02u, pwm %4.1f\n",
tick,
stufe,
(tick - ticks_pro_stufe*stufe),
new_pwm
);
} }
}
void Treppe::setup(){ dimmer->tick = 0;
dimmer->pwm = dimmer->start_pwm;
pwmController.resetDevices(); Serial.printf("stufe %d, ticks %d, delta %f, start %d, ziel %d\n",
// Deactive PCA9685 Phase Balancer due to LED Flickering dimmer->stufe, dimmer->ticks, dimmer->delta_pwm,
// https://github.com/NachtRaveVL/PCA9685-Arduino/issues/15 dimmer->start_pwm, dimmer->ziel_pwm);
// see also lib/PCA9685-Arduin/PCA9685.h:204
pwmController.init(PCA9685_PhaseBalancer_None);
//pwmController.init(PCA9685_PhaseBalancer_Linear);
pwmController.setPWMFrequency(100);
pwmController.setAllChannelsPWM(idle_brightness);
pinMode(A0, INPUT);
pinMode(SENSOR_OBEN, INPUT);
pinMode(SENSOR_UNTEN, INPUT);
pinMode(OE, OUTPUT);
digitalWrite(OE, 0);
Serial.printf("differenz_pwm_pro_tick %f\n", differenz_pwm_pro_tick);
Serial.println("Hello from Treppe");
Serial.print("Treppe: initial parameters: stairs=");
Serial.println(stairs);
} }
void Treppe::print_state_on_change() { void Treppe::print_state_on_change() {
static FSMTreppeModelClass::ExtU_FSMTreppe_T last_in; static FSMTreppeModelClass::ExtU_FSMTreppe_T last_in;
static FSMTreppeModelClass::ExtY_FSMTreppe_T last_out; static FSMTreppeModelClass::ExtY_FSMTreppe_T last_out;
if( if (fsm_inputs.anim_beendet != last_in.anim_beendet ||
fsm_inputs.anim_beendet != last_in.anim_beendet || fsm_inputs.sensor_oben != last_in.sensor_oben ||
fsm_inputs.sensor_oben != last_in.sensor_oben || fsm_inputs.sensor_unten != last_in.sensor_unten ||
fsm_inputs.sensor_unten != last_in.sensor_unten || fsm_inputs.ldr_schwelle != last_in.ldr_schwelle ||
fsm_outputs.dimmrichtung != last_out.dimmrichtung || fsm_outputs.dimmrichtung != last_out.dimmrichtung ||
fsm_outputs.laufrichtung != last_out.laufrichtung || fsm_outputs.laufrichtung != last_out.laufrichtung ||
fsm_outputs.status != last_out.status fsm_outputs.status != last_out.status) {
) {
last_in.anim_beendet = fsm_inputs.anim_beendet; last_in.anim_beendet = fsm_inputs.anim_beendet;
last_in.sensor_oben = fsm_inputs.sensor_oben; last_in.sensor_oben = fsm_inputs.sensor_oben;
last_in.sensor_unten = fsm_inputs.sensor_unten; last_in.sensor_unten = fsm_inputs.sensor_unten;
last_in.ldr_schwelle = fsm_inputs.ldr_schwelle;
last_out.dimmrichtung = fsm_outputs.dimmrichtung;
last_out.laufrichtung = fsm_outputs.laufrichtung;
last_out.status = fsm_outputs.status;
Serial.printf("FSM IN: s_u: %d, s_o: %d, beendet: %d =>", Serial.printf("FSM IN: s_u: %d, s_o: %d, a_b: %d, l_s: %d => ",
fsm_inputs.sensor_oben, fsm_inputs.sensor_unten, fsm_inputs.anim_beendet); fsm_inputs.sensor_oben, fsm_inputs.sensor_unten,
Serial.print(" step => "); fsm_inputs.anim_beendet, fsm_inputs.ldr_schwelle);
Serial.printf("OUT: LR: %d DR: %d ST: %d\n", Serial.printf("OUT: LR: %d DR: %d ST: %d\n", fsm_outputs.laufrichtung,
fsm_outputs.laufrichtung, fsm_outputs.dimmrichtung, fsm_outputs.status); fsm_outputs.dimmrichtung, fsm_outputs.status);
} }
} }
void Treppe::task(){ bool Treppe::read_sensor(int sensor) {
//Serial.printf("LDR: %f\n", ((float)analogRead(A0))/1023.*3.68);
if(finish){ /*
direction = switch_direction; reads sensors with edge detection
state = switch_state;
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};
uint8_t index = 0;
if (sensor == SENSOR_OBEN)
index = 0;
else
index = 1;
if (pegel == 1 && pegel_alt[index] == 0) {
pegel_alt[index] = pegel;
return true;
} else {
pegel_alt[index] = pegel;
return false;
} }
// return static_cast<bool>(pegel);
}
fsm_inputs.ldr_schwelle = true; float Treppe::read_ldr() {
fsm_inputs.sensor_oben = read_sensor(SENSOR_OBEN); /*
Reads Illuminance in Lux
FUTURE USE : show current Illuminance on Webserver in order to calibrate
Voltage Divider 1 (R13, R14):
R13 = 220k, R14 = 82k
V(ADC) = V(in1) * R14/(R13+R14)
-> V(in1) = V(ADC) * (R13+R14)/R14
V(ADC) = analogRead(A0)/1023.00
-> V(in1) = analogRead(A0)/1023.00 * (R13+R14)/R14
= analogRead(A0) * (R13+R14)/(R14*1023.00)
= analogRead(A0) * (220k+82k)/(82k*1023.00)
= analogRead(A0) * 0.0036
Voltage Divider 2 (LDR, R1 || (R13+R14))
R1 = 47k, R13+R14 = 302k -> R1||(R13+R14) = 40,67k
Vcc/V(in1) = R(LDR) / (R1||(R13+R14))
-> R(LDR) = Vcc/V(in1) * (R1||(R13+R14))
R(LDR) = 3.3V * 40.67k / V(in1)
Join formulas:
R(LDR) = 3.3V * 40.67k / (0.0036 * analogRead(A0))
= 37280.00/analogRead(A0)
ldr_ohm = R(LDR)
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 = 6526.6 / (ldr_ohm * ldr_ohm);
return ldr_value;
}
bool Treppe::check_ldr() {
static uint8_t active = 0;
#ifdef LDRDEBUG
Serial.printf("R(LDR) = %f kOhm %f lux\n", ldr_value, lux);
return true;
#endif
// follow up: averaging over many samples?
float ldr = read_ldr();
if (ldr < parameters.ldr_schwelle) {
active = 1;
}
if (ldr > parameters.ldr_schwelle + LDR_HYS) {
active = 0;
}
return active;
}
void Treppe::task() {
#ifdef DEBUG_TIMING
uint32_t m = micros();
#endif
// TODO wenn LDR geändert => idle_pwm_soll anpassen
// fsm_pend.ldr_changed = true;
fsm_inputs.ldr_schwelle = check_ldr();
#ifdef DEBUG_TIMING
Serial.print("1:");
Serial.println(micros() - m);
m = micros();
#endif
fsm_inputs.sensor_oben = read_sensor(SENSOR_OBEN);
fsm_inputs.sensor_unten = read_sensor(SENSOR_UNTEN); fsm_inputs.sensor_unten = read_sensor(SENSOR_UNTEN);
fsm_inputs.anim_beendet = static_cast<bool>(finish); fsm_inputs.anim_beendet = fsm_pend.anim_beendet;
#ifdef DEBUG_TIMING
Serial.print("2:");
Serial.println(micros() - m);
m = micros();
#endif
FSMTreppe_Obj.setExternalInputs(&fsm_inputs); FSMTreppe_Obj.setExternalInputs(&fsm_inputs);
FSMTreppe_Obj.step(); FSMTreppe_Obj.step();
fsm_outputs = FSMTreppe_Obj.getExternalOutputs(); fsm_outputs = FSMTreppe_Obj.getExternalOutputs();
#ifdef DEBUG_TIMING
Serial.print("3:");
Serial.println(micros() - m);
m = micros();
#endif
print_state_on_change(); print_state_on_change();
direction = fsm_outputs.laufrichtung; #ifdef DEBUG_TIMING
state = fsm_outputs.dimmrichtung; Serial.print("4:");
Serial.println(micros() - m);
m = micros();
#endif
// setTick(ticks_treppe); if (fsm_outputs.status == ST_AUFDIMMEN_HOCH ||
// setAnAus(1); fsm_outputs.status == ST_ABDIMMEN_HOCH ||
// setDirection(0); fsm_outputs.status == ST_AUFDIMMEN_RUNTER ||
// setState(0); fsm_outputs.status == ST_ABDIMMEN_RUNTER) {
if (fsm_pend.anim_beendet)
ledsequence(); start_animation(&dimmer_stufen, DIM_STUFEN, parameters.active_pwm,
} idle_pwm_ist);
else
fsm_pend.anim_beendet = dimmer_tick(&dimmer_stufen, DIM_STUFEN);
uint16_t Treppe::setIdle(uint16_t _idle_brightness){ } else if (fsm_outputs.status == ST_AUFDIMMEN_LDR ||
idle_brightness = _idle_brightness; fsm_outputs.status == ST_ABDIMMEN_LDR) {
Serial.println("Treppe: idle brightness changed!"); if (fsm_pend.anim_beendet)
return idle_brightness; start_animation(&dimmer_ldr, DIM_LDR, idle_pwm_ist, 0);
} else
uint16_t Treppe::setActive(uint16_t _active_brightness){ fsm_pend.anim_beendet = dimmer_tick(&dimmer_ldr, DIM_LDR);
active_brightness = _active_brightness; } else if (fsm_outputs.status == ST_RUHEZUSTAND) {
Serial.println("Treppe: active brightness changed!"); if (fsm_pend.ldr_changed) {
return active_brightness; fsm_pend.ldr_changed = false;
} fsm_outputs.dimmrichtung = DR_AUFDIMMEN;
uint16_t Treppe::setTime(uint16_t _time_per_stair){ start_animation(&dimmer_ldr, DIM_LDR, idle_pwm_soll, idle_pwm_ist);
time_per_stair = _time_per_stair; idle_pwm_ist = idle_pwm_soll;
Serial.println("Treppe: time changed!"); }
return time_per_stair; if (!fsm_pend.anim_beendet) {
} fsm_pend.anim_beendet = dimmer_tick(&dimmer_ldr, DIM_LDR);
}
void Treppe::setDirection(uint8_t _direction){
switch_direction = _direction;
Serial.printf("Treppe: switch_direction=%d!\n", switch_direction);
if(finish) Serial.println("apply direction request immediately");
else Serial.println("currently active, dir change afterwards");
// to do: implement state command variable to determine dimm-state
}
void Treppe::setState(uint8_t _state){
if(state == _state) return;
else {
switch_state = _state;
Serial.printf("Treppe: switch_state=%d!\n", switch_state);
if(finish) Serial.println("apply state request immediately");
else Serial.println("currently active, state changes after activity");
} }
#ifdef DEBUG_TIMING
Serial.print("5:");
Serial.println(micros() - m);
#endif
}
void Treppe::setup() {
pwmController.resetDevices();
// Deactive PCA9685 Phase Balancer due to LED Flickering
// https://github.com/NachtRaveVL/PCA9685-Arduino/issues/15
// see also lib/PCA9685-Arduin/PCA9685.h:204
pwmController.init(PCA9685_PhaseBalancer_None);
// pwmController.init(PCA9685_PhaseBalancer_Linear);
pwmController.setPWMFrequency(100);
// pwmController.setAllChannelsPWM(idle_pwm);
pinMode(13, OUTPUT);
pinMode(0, OUTPUT);
digitalWrite(13, HIGH);
digitalWrite(0, HIGH);
pinMode(A0, INPUT);
pinMode(SENSOR_OBEN, INPUT);
pinMode(SENSOR_UNTEN, INPUT);
pinMode(OE, OUTPUT);
digitalWrite(OE, 0);
Serial.printf("Treppe: stufen=%d\n", stufen);
}
void Treppe::set_idle_pwm_max(const uint16_t value,
const vorgabe_typ_t vorgabe_typ) {
if (vorgabe_typ == VORGABE_PROZENT) {
parameters.idle_pwm_max = parameters.active_pwm * value / 100;
} else if (vorgabe_typ == VORGABE_12BIT) {
parameters.idle_pwm_max = value;
}
if (parameters.idle_pwm_max > parameters.active_pwm) {
parameters.idle_pwm_max = parameters.active_pwm;
}
Serial.printf("Treppe: parameters.idle_pwm_max=%d\n",
parameters.idle_pwm_max);
}
void Treppe::set_active_pwm(const uint16_t value,
const vorgabe_typ_t vorgabe_typ) {
if (vorgabe_typ == VORGABE_PROZENT) {
parameters.active_pwm = 4095 * value / 100;
} else if (vorgabe_typ == VORGABE_12BIT) {
parameters.active_pwm = value;
}
if (parameters.active_pwm > 4095) {
parameters.idle_pwm_max = 4095;
}
Serial.printf("Treppe: parameters.active_pwm=%d\n", parameters.active_pwm);
}
void Treppe::set_time_per_stair(uint16_t _time_per_stair) {
parameters.time_per_stair = _time_per_stair;
Serial.printf("Treppe: time_per_stair=%d\n", parameters.time_per_stair);
} }
+81 -76
View File
@@ -1,97 +1,102 @@
#pragma once #ifndef __TREPPE_H
#define __TREPPE_H
#include "FSMTreppe/FSMTreppe2.h" #include "FSMTreppe3/FSMTreppe3.h"
#include "PCA9685.h" #include "PCA9685.h"
#define SENSOR_OBEN 2 // #define LDRDEBUG // comment in to override LDR measurement
#define LDR_HYS 1 // Hysteresis for switching off FSM [lux]
#define SENSOR_OBEN 16
#define SENSOR_UNTEN 12 #define SENSOR_UNTEN 12
#define OE 14 #define OE 14
#define INT_TIME 20 // interrupt intervall [ms] #define INT_TIME 20 // interrupt intervall [ms]
enum vorgabe_typ_t { VORGABE_PROZENT = 0, VORGABE_12BIT = 1 };
class Treppe { class Treppe {
private: private:
const uint8_t stufen;
uint8_t stairs; struct stairway_param_t {
uint16_t time_per_stair = 300; // dimmtime per stair [ms] uint16_t time_ldr = 500;
uint16_t idle_brightness = 100; uint16_t time_per_stair = 300; // dimmtime per stair [ms]
uint16_t active_brightness = 300; uint16_t idle_pwm_max = 100;
uint16_t active_pwm = 2000;
uint16_t ldr_schwelle = 2; // activation value for FSM [lx]
};
stairway_param_t parameters;
uint8_t direction = 0; uint16_t idle_pwm_ist = parameters.idle_pwm_max;
uint8_t switch_direction = 0; uint16_t idle_pwm_soll = 0;
uint8_t state = 0;
uint8_t switch_state = 0;
bool finish = 1;
// alternative struct fsm_pending_inputs_t {
uint32_t tick = 0; bool anim_beendet = true;
uint32_t stufe = 0; bool sensor_unten = false;
uint8_t an_aus = 0; bool sensor_oben = false;
bool ldr_changed = false;
};
fsm_pending_inputs_t fsm_pend;
uint32_t ticks_treppe = 0; struct dimmer_t {
uint32_t ticks_pro_stufe = 0; uint8_t stufe = 0;
float differenz_pwm_pro_tick = 0.0; uint16_t ticks = 0;
// alternative uint16_t tick = 0;
// initialize with i2c-Address 0, use Wire Library float delta_pwm = 0.0;
PCA9685 pwmController; float pwm = 0.0;
FSMTreppeModelClass FSMTreppe_Obj; uint16_t start_pwm = 0;
FSMTreppeModelClass::ExtU_FSMTreppe_T fsm_inputs; uint16_t ziel_pwm = 0;
FSMTreppeModelClass::ExtY_FSMTreppe_T fsm_outputs; };
void print_state_on_change(); enum dimmer_type_t { DIM_STUFEN = 0, DIM_LDR = 1 };
dimmer_t dimmer_stufen;
dimmer_t dimmer_ldr;
const uint8_t FSMTreppe_IN_animation_down = 1U; // initialize with i2c-Address 0, use Wire Library
const uint8_t FSMTreppe_IN_animation_up = 2U; PCA9685 pwmController;
const uint8_t FSMTreppe_IN_idle = 3U; FSMTreppeModelClass FSMTreppe_Obj;
FSMTreppeModelClass::ExtU_FSMTreppe_T fsm_inputs;
FSMTreppeModelClass::ExtY_FSMTreppe_T fsm_outputs;
enum fsm_status_t {
ST_INAKTIV_LDR = 0,
ST_AUFDIMMEN_LDR = 1,
ST_ABDIMMEN_LDR = 2,
ST_RUHEZUSTAND = 3,
ST_AUFDIMMEN_HOCH = 4,
ST_WARTEN_HOCH = 5,
ST_ABDIMMEN_HOCH = 6,
ST_AUFDIMMEN_RUNTER = 7,
ST_WARTEN_RUNTER = 8,
ST_ABDIMMEN_RUNTER = 9
};
enum fsm_laufrichtung_t { LR_RUNTER = 0, LR_HOCH = 1 };
enum fsm_dimmrichtung_t { DR_ABDIMMEN = 0, DR_AUFDIMMEN = 1 };
/* DIMM */
// bool dimmer(dimmer_t* dimmer, bool dim_type);
bool dimmer_tick(dimmer_t *dimmer, bool dim_type);
void start_animation(dimmer_t *dimmer, bool dim_type, uint16_t on_pwm,
uint16_t off_pwm);
// void berechne_dimmer(dimmer_t* dimmer, bool dim_type);
void print_state_on_change();
/* LDR */
bool read_sensor(int sensor);
float read_ldr();
bool check_ldr();
uint8_t softstart_led(uint8_t led, uint16_t startval, uint16_t stopval);
void ledsequence();
void rampe();
bool read_sensor(int sensor) {
int pegel = digitalRead(sensor);
return static_cast<bool>(pegel);
}
public: public:
Treppe(uint8_t _stairs) : stairs(_stairs){ Treppe(uint8_t _stufen) : stufen(_stufen) { FSMTreppe_Obj.initialize(); }
FSMTreppe_Obj.initialize(); ~Treppe() { FSMTreppe_Obj.terminate(); }
void setup();
void task(); // call periodically
// Parameter section
void set_idle_pwm_max(const uint16_t value, const vorgabe_typ_t vorgabe_typ);
void set_active_pwm(const uint16_t value, const vorgabe_typ_t vorgabe_typ);
void set_time_per_stair(uint16_t _time_per_stair);
};
ticks_pro_stufe = time_per_stair / 20; // [ms] #endif // __TREPPE_H
ticks_treppe = ticks_pro_stufe * stairs;
differenz_pwm_pro_tick = (float) (active_brightness - idle_brightness)
/ (float) ticks_pro_stufe;
}
~Treppe() {
FSMTreppe_Obj.terminate();
}
void setup();
void task(); // call periodically
// Parameter section
uint16_t setIdle(uint16_t _idle_brightness);
uint16_t setActive(uint16_t _active_brightness);
uint16_t setTime(uint16_t _time_per_stair);
void setTick(uint32_t _tick) {
tick = _tick;
Serial.printf("Treppe: Tick: %u!\n", tick);
}
uint32_t getTicks() {
return ticks_treppe;
}
// Runtime Parameter section
void setDirection(uint8_t _direction);
void setState(uint8_t _state);
void setAnAus(uint8_t _an_aus) {
an_aus = _an_aus;
}
uint8_t getState() { return state;};
uint8_t getFinished() { return finish;};
uint8_t getDirection() {return direction;};
};
Binary file not shown.
+1 -1
View File
@@ -13,5 +13,5 @@ mem 0x60000000 0x60001fff rw
set serial baud 460800 set serial baud 460800
file .pio/build/debug/firmware.elf file .pio/build/debug/firmware.elf
target remote /dev/ttyUSB0 target remote \\.\COM23
thb loop thb loop
+32 -32
View File
@@ -9,13 +9,14 @@ extern "C" {
#include "user_interface.h" #include "user_interface.h"
} }
// OTA & WEB // OTA & WEB
#include "wifi_credentials.h"
#include "ota.h"
#include "httpserver.h" #include "httpserver.h"
#include "ota.h"
#include "wifi_credentials.h"
#include <EEPROM.h>
// BOARD // BOARD
#define ESP12_LED 2 #define ESP12_LED 2
#define NODEMCU_LED 16 // #define NODEMCU_LED 16
// PWM // PWM
#include "treppe.h" #include "treppe.h"
@@ -28,16 +29,21 @@ const char* ssid = STASSID;
const char* password = STAPSK; const char* password = STAPSK;
// port 80, root directory of server '/' // port 80, root directory of server '/'
HTTPServer httpServer(80, "/"); HTTPServer httpServer(80, "/", &stairs);
uint32_t _t=0; uint32_t _t=0;
#define SP_US(_str,_a) Serial.print(_str); Serial.print(" took: "); Serial.print(_a); Serial.println("us") #define SP_US(_str,_a) Serial.print(_str); Serial.print(" took: "); Serial.print(_a); Serial.println("us")
#define TIMEIF_US(_f, _l, _str) _t=micros(); _f; _t=micros()-_t; if(_t > _l) { SP_US(_str, _t); } #define TIMEIF_US(_f, _l, _str) _t=micros(); _f; _t=micros()-_t; if(_t > (_l)) { SP_US(_str, _t); }
struct { // Struct for wifi-data, 40 Bytes each SSID and PW
char SSID[40] = "";
char PW[40] = "";
} wifi_data;
void timerCallback(void *pArg) void timerCallback(void *pArg)
{ {
*((int *) pArg) += 1; *(static_cast<int *>(pArg)) += 1;
stairs.task(); stairs.task();
} }
@@ -54,14 +60,23 @@ void setup() {
#else #else
Serial.begin(76800); Serial.begin(76800);
#endif #endif
Serial.println("Booting ....");
Serial.println(F("Booting ...."));
//pinMode(NODEMCU_LED, OUTPUT);
pinMode(ESP12_LED, OUTPUT); pinMode(ESP12_LED, OUTPUT);
EEPROM.begin(512); // init virtual "EEPROM" with size 512 Bytes
//strncpy(wifi_data.SSID, "donotconnect", 40);
//strncpy(wifi_data.PW, "unsafe lol", 40);
EEPROM.get(0, wifi_data);
//EEPROM.commit();
Wire.begin(); // Wire must be started first Wire.begin(); // Wire must be started first
Wire.setClock(1000000); // Supported baud rates are 100kHz, 400kHz, and 1000kHz Wire.setClock(1000000); // Supported baud rates are 100kHz, 400kHz, and 1000kHz
stairs.setup();
Serial.println("PCA9685 connected !");
//attachInterrupt(digitalPinToInterrupt(2), int_test, RISING);
//attachInterrupt(digitalPinToInterrupt(12), int_test, RISING);
WiFi.mode(WIFI_STA); WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password); WiFi.begin(ssid, password);
@@ -82,41 +97,26 @@ void setup() {
httpServer.start(); httpServer.start();
httpServer.start_apps(); httpServer.start_apps();
Serial.println("HTTP server started !"); Serial.println("HTTP server started !");
stairs.setup();
Serial.println("PCA9685 connected !");
//attachInterrupt(digitalPinToInterrupt(2), int_test, RISING);
//attachInterrupt(digitalPinToInterrupt(12), int_test, RISING);
os_timer_setfn(&timer1, timerCallback, &timer_flag); os_timer_setfn(&timer1, timerCallback, &timer_flag);
os_timer_arm(&timer1, 20, true); os_timer_arm(&timer1, 20, true);
}
#include <random> Serial.println("SSID: " + String(wifi_data.SSID) + " PW: " + String(wifi_data.PW));
}
uint32_t c = 0; uint32_t c = 0;
void loop() { void loop() {
// if(stairs.getState() == 0) { if(inter != 0u){
// delay(1000);
// // uint32_t t = rand() % stairs.getTicks();
// // uint32_t d = rand() % 2;
// // stairs.setTick(t);
// // stairs.setDirection(d);
// stairs.setDirection(!stairs.getDirection());
// stairs.setState(1);
// }
if(inter){
Serial.printf("interrupt\n"); Serial.printf("interrupt\n");
inter = 0; inter = 0;
} }
if(c++%1000000 == 0) if(c++%1000000 == 0) { { {
httpServer.logt("[%d] starting :)\n", c); httpServer.logt("[%d] starting :)\n", c);
}
}
}
TIMEIF_US(ArduinoOTA.handle(), 10000, "OTA"); TIMEIF_US(ArduinoOTA.handle(), 10000, "OTA");
TIMEIF_US(httpServer.handleClient(), 10000, "HTTP"); TIMEIF_US(httpServer.handleClient(), 10000, "HTTP");
+12 -2
View File
@@ -16,13 +16,23 @@ data_dir = data_gz
[env:hardware] [env:hardware]
platform = espressif8266 platform = espressif8266
board = nodemcuv2 ; board = nodemcuv2
board = huzzah
framework = arduino framework = arduino
; for pio check
; check_tool = cppcheck
check_tool = clangtidy
check_flags =
; clangtidy: --fix-errors
clangtidy: lib/httpserver/* lib/treppe/* lib/PCA9685-Arduino/*
check_skip_packages = yes
board_build.filesystem = littlefs board_build.filesystem = littlefs
board_build.ldscript = eagle.flash.4m1m.ld board_build.ldscript = eagle.flash.4m1m.ld
extra_scripts = pre:create_gz_files.py extra_scripts = pre:create_gz_files.py
monitor_speed = 115200 monitor_speed = 76800
[env:serial] [env:serial]
extends = env:hardware extends = env:hardware