Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
776931c0ad | ||
|
|
e22b4b6fe1 | ||
|
|
cad534bffe | ||
|
|
3b44adb6fa | ||
|
|
cc0bd1473f | ||
|
|
58124d27bf | ||
|
|
9ad118814a | ||
|
|
270f8dd093 | ||
|
|
fde0ae4781 | ||
|
|
b87ce8c75d | ||
|
|
e372c87836 | ||
|
|
f8478d7742 | ||
|
|
a3d6923fec | ||
|
|
7bfa22187d | ||
|
|
7a8affae32 | ||
|
|
e48dd7c4c4 | ||
|
|
4fe9ab92e0 | ||
|
|
f2ac4cdc64 | ||
|
|
be902401d1 | ||
|
|
020e93bca2 | ||
|
|
61dfdc2258 | ||
|
|
a98e3c8eab |
@@ -11,6 +11,12 @@
|
||||
|
||||
____
|
||||
|
||||
#### #12 Less reboots due to memory leakage
|
||||
|
||||
* Issue: #414 & #425 #430
|
||||
|
||||
|
||||
|
||||
#### #11 MQTT - configurable payload
|
||||
|
||||
* https://github.com/jomjol/AI-on-the-edge-device/issues/344
|
||||
|
||||
24
README.md
@@ -6,6 +6,8 @@ This is an example of Artificial Intelligence (AI) calculations on a very cheap
|
||||
|
||||
A 3d-printable housing can be found here: https://www.thingiverse.com/thing:4573481
|
||||
|
||||
or here https://www.thingiverse.com/thing:5028229
|
||||
|
||||
respectively ESP32-Cam housing only: https://www.thingiverse.com/thing:4571627
|
||||
|
||||
<img src="https://raw.githubusercontent.com/jomjol/AI-on-the-edge-device/master/images/watermeter_all.jpg" width="200"><img src="https://raw.githubusercontent.com/jomjol/AI-on-the-edge-device/master/images/main.jpg" width="200"><img src="https://raw.githubusercontent.com/jomjol/AI-on-the-edge-device/master/images/size.png" width="200">
|
||||
@@ -45,6 +47,28 @@ In other cases you can contact the developer via email: <img src="https://raw.gi
|
||||
|
||||
**General remark:** Beside the `firmware.bin`, typically also the content of `/html` needs to be updated!
|
||||
|
||||
##### 9.2.0 - External Illumination (2021-12-02)
|
||||
|
||||
- Direct JSON access: ``http://IP-ADRESS/json``
|
||||
- Error message in log file in case camera error during startup
|
||||
- Upgrade analog CNN to v9.1.0
|
||||
- Upgrade digital CNN to v13.3.0 (added new images)
|
||||
- html: support of different ports
|
||||
|
||||
##### 9.1.1 - External Illumination (2021-11-16)
|
||||
|
||||
- NEW 9.1.1 bug fix: LED implemenetation
|
||||
- External LEDs: change control mode (resolve bug with more than 2 LEDs)
|
||||
- Additional info into log file
|
||||
- Bug fix: decimal shift, html, log file
|
||||
|
||||
##### 9.0.0 - External Illumination (2021-10-23)
|
||||
|
||||
* Implementation of external illumination to adjust positioning, brightness and color of the illumination now individually
|
||||
* Technical details can be found in the wiki: https://github.com/jomjol/AI-on-the-edge-device/wiki/External-LED
|
||||
<img src="https://raw.githubusercontent.com/jomjol/ai-on-the-edge-device/master/images/intern_vs_external.jpg" width="500">
|
||||
* New housing published for external LEDs and small clearing: https://www.thingiverse.com/thing:5028229
|
||||
|
||||
|
||||
|
||||
##### 8.5.0 - Multi Meter Support (2021-10-07)
|
||||
|
||||
@@ -400,24 +400,19 @@ bool GpioHandler::readConfig()
|
||||
|
||||
if (gpioExtLED > 0)
|
||||
{
|
||||
// LogFile.WriteToFile("Startsequence 06");
|
||||
// LogFile.WriteToFile("Startsequence 06"); // Nremove
|
||||
// vTaskDelay( xDelay );
|
||||
// xDelay = 5000 / portTICK_PERIOD_MS;
|
||||
// printf("main: sleep for : %ldms\n", (long) xDelay);
|
||||
|
||||
SmartLed leds( LED_WS2812, 2, GPIO_NUM_12, 0, DoubleBuffer );
|
||||
// SmartLed leds( LED_WS2812, 2, GPIO_NUM_12, 0, DoubleBuffer );
|
||||
|
||||
|
||||
leds[ 0 ] = Rgb{ 255, 0, 0 };
|
||||
leds[ 1 ] = Rgb{ 255, 255, 255 };
|
||||
leds.show();
|
||||
/*
|
||||
// _SmartLED = new SmartLed(LEDType, LEDNumbers, gpioExtLED, 0, DoubleBuffer);
|
||||
_SmartLED = new SmartLed( LED_WS2812, 2, GPIO_NUM_12, 0, DoubleBuffer );
|
||||
(*_SmartLED)[ 0 ] = Rgb{ 255, 0, 0 };
|
||||
(*_SmartLED)[ 1 ] = LEDColor;
|
||||
_SmartLED->show();
|
||||
*/
|
||||
// leds[ 0 ] = Rgb{ 255, 0, 0 };
|
||||
// leds[ 1 ] = Rgb{ 255, 255, 255 };
|
||||
// leds.show();
|
||||
// SmartLed leds = new SmartLed(LEDType, LEDNumbers, gpioExtLED, 0, DoubleBuffer);
|
||||
// _SmartLED = new SmartLed( LED_WS2812, 2, GPIO_NUM_12, 0, DoubleBuffer );
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -565,18 +560,41 @@ void GpioHandler::flashLightEnable(bool value)
|
||||
{
|
||||
if (it->second->getMode() == GPIO_PIN_MODE_EXTERNAL_FLASH_WS281X)
|
||||
{
|
||||
#ifdef __LEDGLOBAL
|
||||
if (leds_global == NULL) {
|
||||
ESP_LOGI(TAG_SERVERGPIO, "init SmartLed: LEDNumber=%d, GPIO=%d", LEDNumbers, (int)it->second->getGPIO());
|
||||
leds_global = new SmartLed( LEDType, LEDNumbers, it->second->getGPIO(), 0, DoubleBuffer );
|
||||
} else {
|
||||
// wait until we can update: https://github.com/RoboticsBrno/SmartLeds/issues/10#issuecomment-386921623
|
||||
leds_global->wait();
|
||||
}
|
||||
#else
|
||||
SmartLed leds( LEDType, LEDNumbers, it->second->getGPIO(), 0, DoubleBuffer );
|
||||
#endif
|
||||
|
||||
if (value)
|
||||
{
|
||||
for (int i = 0; i < LEDNumbers; ++i)
|
||||
#ifdef __LEDGLOBAL
|
||||
(*leds_global)[i] = LEDColor;
|
||||
#else
|
||||
leds[i] = LEDColor;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < LEDNumbers; ++i)
|
||||
#ifdef __LEDGLOBAL
|
||||
(*leds_global)[i] = Rgb{0, 0, 0};
|
||||
#else
|
||||
leds[i] = Rgb{0, 0, 0};
|
||||
#endif
|
||||
}
|
||||
leds.show();
|
||||
#ifdef __LEDGLOBAL
|
||||
leds_global->show();
|
||||
#else
|
||||
leds.show();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,6 +11,9 @@
|
||||
|
||||
//#include "ClassControllCamera.h"
|
||||
|
||||
// wenn __LEDGLOBAL definiert ist, wird eine globale Variable für die LED-Ansteuerung verwendet, ansonsten lokal und jedesmal neu
|
||||
#define __LEDGLOBAL
|
||||
|
||||
typedef enum {
|
||||
GPIO_PIN_MODE_DISABLED = 0x0,
|
||||
GPIO_PIN_MODE_INPUT = 0x1,
|
||||
@@ -86,7 +89,9 @@ private:
|
||||
int LEDNumbers = 2;
|
||||
Rgb LEDColor = Rgb{ 255, 255, 255 };
|
||||
LedType LEDType = LED_WS2812;
|
||||
|
||||
#ifdef __LEDGLOBAL
|
||||
SmartLed *leds_global = NULL;
|
||||
#endif
|
||||
|
||||
bool readConfig();
|
||||
void clear();
|
||||
|
||||
@@ -624,4 +624,30 @@ esp_err_t ClassFlowControll::GetJPGStream(std::string _fn, httpd_req_t *req)
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
string ClassFlowControll::getJSON()
|
||||
{
|
||||
std::vector<NumberPost*>* NUMBERS = flowpostprocessing->GetNumbers();
|
||||
|
||||
std::string json="{\n";
|
||||
|
||||
for (int i = 0; i < (*NUMBERS).size(); ++i)
|
||||
{
|
||||
json += "\"" + (*NUMBERS)[i]->name + "\":\n";
|
||||
json += " {\n";
|
||||
json += " \"value\": " + (*NUMBERS)[i]->ReturnValueNoError + ",\n";
|
||||
json += " \"raw\": \"" + (*NUMBERS)[i]->ReturnRawValue + "\",\n";
|
||||
json += " \"error\": \"" + (*NUMBERS)[i]->ErrorMessageText + "\",\n";
|
||||
json += " \"rate\": " + std::to_string((*NUMBERS)[i]->FlowRateAct) + ",\n";
|
||||
json += " \"timestamp\": \"" + (*NUMBERS)[i]->timeStamp + "\"\n";
|
||||
if ((i+1) < (*NUMBERS).size())
|
||||
json += " },\n";
|
||||
else
|
||||
json += " }\n";
|
||||
}
|
||||
json += "}";
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ public:
|
||||
string UpdatePrevalue(std::string _newvalue, std::string _numbers, bool _extern);
|
||||
string GetPrevalue(std::string _number = "");
|
||||
bool ReadParameter(FILE* pfile, string& aktparamgraph);
|
||||
string getJSON();
|
||||
|
||||
string TranslateAktstatus(std::string _input);
|
||||
|
||||
|
||||
@@ -492,8 +492,6 @@ void ClassFlowPostProcessing::InitNUMBERS()
|
||||
_number->MaxRateValue = 0.1;
|
||||
_number->useMaxRateValue = false;
|
||||
_number->checkDigitIncreaseConsistency = false;
|
||||
_number->PreValueOkay = false;
|
||||
_number->useMaxRateValue = false;
|
||||
_number->DecimalShift = 0;
|
||||
_number->DecimalShiftInitial = 0;
|
||||
_number->isExtendedResolution = false;
|
||||
@@ -568,12 +566,8 @@ bool ClassFlowPostProcessing::doFlow(string zwtime)
|
||||
time_t imagetime = 0;
|
||||
string rohwert;
|
||||
|
||||
// ErrorMessageText = "";
|
||||
|
||||
// Update Nachkomma, da sich beim Wechsel von CNNType Auto --> xyz auch die Nachkommastellen ändern können:
|
||||
|
||||
|
||||
|
||||
imagetime = flowMakeImage->getTimeImageTaken();
|
||||
if (imagetime == 0)
|
||||
time(&imagetime);
|
||||
@@ -662,7 +656,7 @@ bool ClassFlowPostProcessing::doFlow(string zwtime)
|
||||
zwvalue = RundeOutput(NUMBERS[j]->Value, NUMBERS[j]->Nachkomma);
|
||||
}
|
||||
|
||||
if (NUMBERS[j]->useMaxRateValue && (abs(NUMBERS[j]->Value - NUMBERS[j]->PreValue) > NUMBERS[j]->MaxRateValue))
|
||||
if (NUMBERS[j]->useMaxRateValue && ((abs(NUMBERS[j]->Value - NUMBERS[j]->PreValue) > NUMBERS[j]->MaxRateValue)))
|
||||
{
|
||||
NUMBERS[j]->ErrorMessageText = NUMBERS[j]->ErrorMessageText + "Rate too high - Read: " + RundeOutput(NUMBERS[j]->Value, NUMBERS[j]->Nachkomma) + " - Pre: " + RundeOutput(NUMBERS[j]->PreValue, NUMBERS[j]->Nachkomma);
|
||||
NUMBERS[j]->Value = NUMBERS[j]->PreValue;
|
||||
@@ -688,6 +682,8 @@ bool ClassFlowPostProcessing::doFlow(string zwtime)
|
||||
UpdatePreValueINI = true;
|
||||
}
|
||||
}
|
||||
string _zw = "PostProcessing - Raw: " + NUMBERS[j]->ReturnRawValue + " Value: " + NUMBERS[j]->ReturnValue + " Error: " + NUMBERS[j]->ErrorMessageText;
|
||||
LogFile.WriteToFile(_zw);
|
||||
}
|
||||
|
||||
SavePreValue();
|
||||
@@ -724,8 +720,8 @@ void ClassFlowPostProcessing::UpdateNachkommaDecimalShift()
|
||||
{
|
||||
// printf("Nur digital + analog\n");
|
||||
|
||||
NUMBERS[j]->Nachkomma = NUMBERS[j]->analog_roi->ROI.size();
|
||||
NUMBERS[j]->DecimalShift = NUMBERS[j]->DecimalShiftInitial;
|
||||
NUMBERS[j]->Nachkomma = NUMBERS[j]->analog_roi->ROI.size() - NUMBERS[j]->DecimalShift;
|
||||
|
||||
if (NUMBERS[j]->isExtendedResolution && flowAnalog->isExtendedResolution()) // extended resolution ist an und soll auch bei dieser Ziffer verwendet werden
|
||||
NUMBERS[j]->Nachkomma = NUMBERS[j]->Nachkomma+1;
|
||||
|
||||
@@ -80,7 +80,7 @@ void memCopyGen(uint8_t* _source, uint8_t* _target, int _size)
|
||||
|
||||
FILE* OpenFileAndWait(const char* nm, const char* _mode, int _waitsec)
|
||||
{
|
||||
printf("open config file %s in mode %s\n", nm, _mode);
|
||||
printf("open file %s in mode %s\n", nm, _mode);
|
||||
FILE *pfile = fopen(nm, _mode);
|
||||
|
||||
/*
|
||||
|
||||
@@ -189,6 +189,36 @@ esp_err_t handler_doflow(httpd_req_t *req)
|
||||
};
|
||||
|
||||
|
||||
esp_err_t handler_json(httpd_req_t *req)
|
||||
{
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
LogFile.WriteHeapInfo("handler_json - Start");
|
||||
#endif
|
||||
|
||||
|
||||
printf("handler_JSON uri:\n"); printf(req->uri); printf("\n");
|
||||
|
||||
char _query[100];
|
||||
char _size[10];
|
||||
|
||||
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
|
||||
httpd_resp_set_type(req, "application/json");
|
||||
|
||||
std::string zw = tfliteflow.getJSON();
|
||||
if (zw.length() > 0)
|
||||
httpd_resp_sendstr_chunk(req, zw.c_str());
|
||||
|
||||
string query = std::string(_query);
|
||||
|
||||
/* Respond with an empty chunk to signal HTTP response completion */
|
||||
httpd_resp_sendstr_chunk(req, NULL);
|
||||
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
LogFile.WriteHeapInfo("handler_JSON - Done");
|
||||
#endif
|
||||
return ESP_OK;
|
||||
};
|
||||
|
||||
|
||||
|
||||
esp_err_t handler_wasserzaehler(httpd_req_t *req)
|
||||
@@ -710,4 +740,10 @@ void register_server_tflite_uri(httpd_handle_t server)
|
||||
camuri.handler = handler_wasserzaehler;
|
||||
camuri.user_ctx = (void*) "Wasserzaehler";
|
||||
httpd_register_uri_handler(server, &camuri);
|
||||
|
||||
camuri.uri = "/json";
|
||||
camuri.handler = handler_json;
|
||||
camuri.user_ctx = (void*) "JSON";
|
||||
httpd_register_uri_handler(server, &camuri);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,132 +0,0 @@
|
||||
#include "Color.h"
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <cassert>
|
||||
|
||||
namespace {
|
||||
|
||||
// Int -> fixed point
|
||||
int up( int x ) { return x * 255; }
|
||||
|
||||
} // namespace
|
||||
|
||||
int iRgbSqrt( int num ) {
|
||||
// https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Binary_numeral_system_.28base_2.29
|
||||
assert( "sqrt input should be non-negative" && num >= 0 );
|
||||
assert( "sqrt input should no exceed 16 bits" && num <= 0xFFFF );
|
||||
int res = 0;
|
||||
int bit = 1 << 16;
|
||||
while ( bit > num )
|
||||
bit >>= 2;
|
||||
while ( bit != 0 ) {
|
||||
if ( num >= res + bit ) {
|
||||
num -= res + bit;
|
||||
res = ( res >> 1 ) + bit;
|
||||
} else
|
||||
res >>= 1;
|
||||
bit >>= 2;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
Rgb::Rgb( Hsv y ) {
|
||||
// https://stackoverflow.com/questions/24152553/hsv-to-rgb-and-back-without-floating-point-math-in-python
|
||||
// greyscale
|
||||
if( y.s == 0 ) {
|
||||
r = g = b = y.v;
|
||||
return;
|
||||
}
|
||||
|
||||
const int region = y.h / 43;
|
||||
const int remainder = ( y.h - ( region * 43 ) ) * 6;
|
||||
|
||||
const int p = ( y.v * ( 255 - y.s ) ) >> 8;
|
||||
const int q = ( y.v * ( 255 - ( ( y.s * remainder ) >> 8 ) ) ) >> 8;
|
||||
const int t = ( y.v * ( 255 - ( ( y.s * (255 -remainder ) ) >> 8 ) ) ) >> 8;
|
||||
|
||||
switch( region ) {
|
||||
case 0: r = y.v; g = t; b = p; break;
|
||||
case 1: r = q; g = y.v; b = p; break;
|
||||
case 2: r = p; g = y.v; b = t; break;
|
||||
case 3: r = p; g = q; b = y.v; break;
|
||||
case 4: r = t; g = p; b = y.v; break;
|
||||
case 5: r = y.v; g = p; b = q; break;
|
||||
default: __builtin_trap();
|
||||
}
|
||||
|
||||
a = y.a;
|
||||
}
|
||||
|
||||
Rgb& Rgb::operator=( Hsv hsv ) {
|
||||
Rgb r{ hsv };
|
||||
swap( r );
|
||||
return *this;
|
||||
}
|
||||
|
||||
Rgb Rgb::operator+( Rgb in ) const {
|
||||
auto copy = *this;
|
||||
copy += in;
|
||||
return copy;
|
||||
}
|
||||
|
||||
Rgb& Rgb::operator+=( Rgb in ) {
|
||||
unsigned int red = r + in.r;
|
||||
r = ( red < 255 ) ? red : 255;
|
||||
unsigned int green = g + in.g;
|
||||
g = ( green < 255 ) ? green : 255;
|
||||
unsigned int blue = b + in.b;
|
||||
b = ( blue < 255 ) ? blue : 255;
|
||||
return *this;
|
||||
}
|
||||
|
||||
Rgb& Rgb::blend( Rgb in ) {
|
||||
unsigned int inAlpha = in.a * ( 255 - a );
|
||||
unsigned int alpha = a + inAlpha;
|
||||
r = iRgbSqrt( ( ( r * r * a ) + ( in.r * in.r * inAlpha ) ) / alpha );
|
||||
g = iRgbSqrt( ( ( g * g * a ) + ( in.g * in.g * inAlpha ) ) / alpha );
|
||||
b = iRgbSqrt( ( ( b * b * a ) + ( in.b * in.b * inAlpha ) ) / alpha );
|
||||
a = alpha;
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint8_t IRAM_ATTR Rgb::getGrb( int idx ) {
|
||||
switch ( idx ) {
|
||||
case 0: return g;
|
||||
case 1: return r;
|
||||
case 2: return b;
|
||||
}
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
Hsv::Hsv( Rgb r ) {
|
||||
int min = std::min( r.r, std::min( r.g, r.b ) );
|
||||
int max = std::max( r.r, std::max( r.g, r.b ) );
|
||||
int chroma = max - min;
|
||||
|
||||
v = max;
|
||||
if ( chroma == 0 ) {
|
||||
h = s = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
s = up( chroma ) / max;
|
||||
int hh;
|
||||
if ( max == r.r )
|
||||
hh = ( up( int( r.g ) - int( r.b ) ) ) / chroma / 6;
|
||||
else if ( max == r.g )
|
||||
hh = 255 / 3 + ( up( int( r.b ) - int( r.r ) ) ) / chroma / 6;
|
||||
else
|
||||
hh = 2 * 255 / 3 + ( up( int( r.r ) - int( r.g ) ) ) / chroma / 6;
|
||||
|
||||
if ( hh < 0 )
|
||||
hh += 255;
|
||||
h = hh;
|
||||
|
||||
a = r.a;
|
||||
}
|
||||
|
||||
Hsv& Hsv::operator=( Rgb rgb ) {
|
||||
Hsv h{ rgb };
|
||||
swap( h );
|
||||
return *this;
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include "esp_attr.h"
|
||||
union Hsv;
|
||||
|
||||
union Rgb {
|
||||
struct __attribute__ ((packed)) {
|
||||
uint8_t r, g, b, a;
|
||||
};
|
||||
uint32_t value;
|
||||
|
||||
Rgb( uint8_t r = 0, uint8_t g = 0, uint8_t b = 0, uint8_t a = 255 ) : r( r ), g( g ), b( b ), a( a ) {}
|
||||
Rgb( Hsv c );
|
||||
Rgb& operator=( Rgb rgb ) { swap( rgb ); return *this; }
|
||||
Rgb& operator=( Hsv hsv );
|
||||
Rgb operator+( Rgb in ) const;
|
||||
Rgb& operator+=( Rgb in );
|
||||
bool operator==( Rgb in ) const { return in.value == value; }
|
||||
Rgb& blend( Rgb in );
|
||||
void swap( Rgb& o ) { value = o.value; }
|
||||
void linearize() {
|
||||
r = channelGamma(r);
|
||||
g = channelGamma(g);
|
||||
b = channelGamma(b);
|
||||
}
|
||||
|
||||
uint8_t IRAM_ATTR getGrb( int idx );
|
||||
|
||||
void stretchChannels( uint8_t maxR, uint8_t maxG, uint8_t maxB ) {
|
||||
r = stretch( r, maxR );
|
||||
g = stretch( g, maxG );
|
||||
b = stretch( b, maxB );
|
||||
}
|
||||
|
||||
void stretchChannelsEvenly( uint8_t max ) {
|
||||
stretchChannels( max, max, max );
|
||||
}
|
||||
|
||||
private:
|
||||
uint8_t stretch( int value, uint8_t max ) {
|
||||
return ( value * max ) >> 8;
|
||||
}
|
||||
|
||||
uint8_t channelGamma( int channel ) {
|
||||
/* The optimal gamma correction is x^2.8. However, this is expensive to
|
||||
* compute. Therefore, we use x^3 for gamma correction. Also, we add a
|
||||
* bias as the WS2812 LEDs do not turn on for values less than 4. */
|
||||
if (channel == 0)
|
||||
return channel;
|
||||
channel = channel * channel * channel * 251;
|
||||
channel >>= 24;
|
||||
return static_cast< uint8_t >( 4 + channel );
|
||||
}
|
||||
};
|
||||
|
||||
union Hsv {
|
||||
struct __attribute__ ((packed)) {
|
||||
uint8_t h, s, v, a;
|
||||
};
|
||||
uint32_t value;
|
||||
|
||||
Hsv( uint8_t h, uint8_t s = 0, uint8_t v = 0, uint8_t a = 255 ) : h( h ), s( s ), v( v ), a( a ) {}
|
||||
Hsv( Rgb r );
|
||||
Hsv& operator=( Hsv h ) { swap( h ); return *this; }
|
||||
Hsv& operator=( Rgb rgb );
|
||||
bool operator==( Hsv in ) const { return in.value == value; }
|
||||
void swap( Hsv& o ) { value = o.value; }
|
||||
};
|
||||
@@ -1,63 +0,0 @@
|
||||
#include "SmartLeds.h"
|
||||
|
||||
IsrCore SmartLed::_interruptCore = CoreCurrent;
|
||||
intr_handle_t SmartLed::_interruptHandle = NULL;
|
||||
|
||||
SmartLed*& IRAM_ATTR SmartLed::ledForChannel( int channel ) {
|
||||
static SmartLed* table[8] = { nullptr };
|
||||
assert( channel < 8 );
|
||||
return table[ channel ];
|
||||
}
|
||||
|
||||
void IRAM_ATTR SmartLed::interruptHandler(void*) {
|
||||
for (int channel = 0; channel != 8; channel++) {
|
||||
auto self = ledForChannel( channel );
|
||||
|
||||
if ( RMT.int_st.val & (1 << (24 + channel ) ) ) { // tx_thr_event
|
||||
if ( self )
|
||||
self->copyRmtHalfBlock();
|
||||
RMT.int_clr.val |= 1 << ( 24 + channel );
|
||||
} else if ( RMT.int_st.val & ( 1 << (3 * channel ) ) ) { // tx_end
|
||||
if ( self )
|
||||
xSemaphoreGiveFromISR( self->_finishedFlag, nullptr );
|
||||
RMT.int_clr.val |= 1 << ( 3 * channel );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IRAM_ATTR SmartLed::copyRmtHalfBlock() {
|
||||
int offset = detail::MAX_PULSES * _halfIdx;
|
||||
_halfIdx = !_halfIdx;
|
||||
int len = 3 - _componentPosition + 3 * ( _count - 1 );
|
||||
len = std::min( len, detail::MAX_PULSES / 8 );
|
||||
|
||||
if ( !len ) {
|
||||
for ( int i = 0; i < detail::MAX_PULSES; i++) {
|
||||
RMTMEM.chan[ _channel].data32[i + offset ].val = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int i;
|
||||
for ( i = 0; i != len && _pixelPosition != _count; i++ ) {
|
||||
uint8_t val = _buffer[ _pixelPosition ].getGrb( _componentPosition );
|
||||
for ( int j = 0; j != 8; j++, val <<= 1 ) {
|
||||
int bit = val >> 7;
|
||||
int idx = i * 8 + offset + j;
|
||||
RMTMEM.chan[ _channel ].data32[ idx ].val = _bitToRmt[ bit & 0x01 ].value;
|
||||
}
|
||||
if ( _pixelPosition == _count - 1 && _componentPosition == 2 ) {
|
||||
RMTMEM.chan[ _channel ].data32[ i * 8 + offset + 7 ].duration1 =
|
||||
_timing.TRS / ( detail::RMT_DURATION_NS * detail::DIVIDER );
|
||||
}
|
||||
|
||||
_componentPosition++;
|
||||
if ( _componentPosition == 3 ) {
|
||||
_componentPosition = 0;
|
||||
_pixelPosition++;
|
||||
}
|
||||
}
|
||||
|
||||
for ( i *= 8; i != detail::MAX_PULSES; i++ ) {
|
||||
RMTMEM.chan[ _channel ].data32[ i + offset ].val = 0;
|
||||
}
|
||||
}
|
||||
@@ -1,530 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
* A C++ driver for the WS2812 LEDs using the RMT peripheral on the ESP32.
|
||||
*
|
||||
* Jan "yaqwsx" Mrázek <email@honzamrazek.cz>
|
||||
*
|
||||
* Based on the work by Martin F. Falatic - https://github.com/FozzTexx/ws2812-demo
|
||||
*/
|
||||
|
||||
/*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <memory>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
#if defined ( ARDUINO )
|
||||
extern "C" { // ...someone forgot to put in the includes...
|
||||
#include "esp32-hal.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "esp_ipc.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "driver/periph_ctrl.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "soc/rmt_struct.h"
|
||||
#include <driver/spi_master.h>
|
||||
#include "esp_idf_version.h"
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL( 4, 0, 0 )
|
||||
#include "soc/dport_reg.h"
|
||||
#endif
|
||||
}
|
||||
#elif defined ( ESP_PLATFORM )
|
||||
extern "C" { // ...someone forgot to put in the includes...
|
||||
#include <esp_intr_alloc.h>
|
||||
#include <esp_ipc.h>
|
||||
#include <driver/gpio.h>
|
||||
#include <freertos/FreeRTOS.h>
|
||||
#include <freertos/semphr.h>
|
||||
#include <soc/dport_reg.h>
|
||||
#include <soc/gpio_sig_map.h>
|
||||
#include <soc/rmt_struct.h>
|
||||
#include <driver/spi_master.h>
|
||||
}
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#include "Color.h"
|
||||
|
||||
namespace detail {
|
||||
|
||||
struct TimingParams {
|
||||
uint32_t T0H;
|
||||
uint32_t T1H;
|
||||
uint32_t T0L;
|
||||
uint32_t T1L;
|
||||
uint32_t TRS;
|
||||
};
|
||||
|
||||
union RmtPulsePair {
|
||||
struct {
|
||||
int duration0:15;
|
||||
int level0:1;
|
||||
int duration1:15;
|
||||
int level1:1;
|
||||
};
|
||||
uint32_t value;
|
||||
};
|
||||
|
||||
static const int DIVIDER = 4; // 8 still seems to work, but timings become marginal
|
||||
static const int MAX_PULSES = 32; // A channel has a 64 "pulse" buffer - we use half per pass
|
||||
static const double RMT_DURATION_NS = 12.5; // minimum time of a single RMT duration based on clock ns
|
||||
|
||||
} // namespace detail
|
||||
|
||||
using LedType = detail::TimingParams;
|
||||
|
||||
static const LedType LED_WS2812 = { 350, 700, 800, 600, 50000 };
|
||||
static const LedType LED_WS2812B = { 400, 850, 850, 400, 50100 };
|
||||
static const LedType LED_SK6812 = { 300, 600, 900, 600, 80000 };
|
||||
static const LedType LED_WS2813 = { 350, 800, 350, 350, 300000 };
|
||||
|
||||
enum BufferType { SingleBuffer = 0, DoubleBuffer };
|
||||
|
||||
enum IsrCore { CoreFirst = 0, CoreSecond = 1, CoreCurrent = 2};
|
||||
|
||||
class SmartLed {
|
||||
public:
|
||||
// The RMT interrupt must not run on the same core as WiFi interrupts, otherwise SmartLeds
|
||||
// can't fill the RMT buffer fast enough, resulting in rendering artifacts.
|
||||
// Usually, that means you have to set isrCore == CoreSecond.
|
||||
//
|
||||
// If you use anything other than CoreCurrent, the FreeRTOS scheduler MUST be already running,
|
||||
// so you can't use it if you define SmartLed as global variable.
|
||||
SmartLed( const LedType& type, int count, int pin, int channel = 0, BufferType doubleBuffer = SingleBuffer, IsrCore isrCore = CoreCurrent)
|
||||
: _timing( type ),
|
||||
_channel( channel ),
|
||||
_count( count ),
|
||||
_firstBuffer( new Rgb[ count ] ),
|
||||
_secondBuffer( doubleBuffer ? new Rgb[ count ] : nullptr ),
|
||||
_finishedFlag( xSemaphoreCreateBinary() )
|
||||
{
|
||||
assert( channel >= 0 && channel < 8 );
|
||||
assert( ledForChannel( channel ) == nullptr );
|
||||
|
||||
xSemaphoreGive( _finishedFlag );
|
||||
|
||||
DPORT_SET_PERI_REG_MASK( DPORT_PERIP_CLK_EN_REG, DPORT_RMT_CLK_EN );
|
||||
DPORT_CLEAR_PERI_REG_MASK( DPORT_PERIP_RST_EN_REG, DPORT_RMT_RST );
|
||||
|
||||
PIN_FUNC_SELECT( GPIO_PIN_MUX_REG[ pin ], 2 );
|
||||
gpio_set_direction( static_cast< gpio_num_t >( pin ), GPIO_MODE_OUTPUT );
|
||||
gpio_matrix_out( static_cast< gpio_num_t >( pin ), RMT_SIG_OUT0_IDX + _channel, 0, 0 );
|
||||
initChannel( _channel );
|
||||
|
||||
RMT.tx_lim_ch[ _channel ].limit = detail::MAX_PULSES;
|
||||
RMT.int_ena.val |= 1 << ( 24 + _channel );
|
||||
RMT.int_ena.val |= 1 << ( 3 * _channel );
|
||||
|
||||
_bitToRmt[ 0 ].level0 = 1;
|
||||
_bitToRmt[ 0 ].level1 = 0;
|
||||
_bitToRmt[ 0 ].duration0 = _timing.T0H / ( detail::RMT_DURATION_NS * detail::DIVIDER );
|
||||
_bitToRmt[ 0 ].duration1 = _timing.T0L / ( detail::RMT_DURATION_NS * detail::DIVIDER );
|
||||
|
||||
_bitToRmt[ 1 ].level0 = 1;
|
||||
_bitToRmt[ 1 ].level1 = 0;
|
||||
_bitToRmt[ 1 ].duration0 = _timing.T1H / ( detail::RMT_DURATION_NS * detail::DIVIDER );
|
||||
_bitToRmt[ 1 ].duration1 = _timing.T1L / ( detail::RMT_DURATION_NS * detail::DIVIDER );
|
||||
|
||||
if ( !anyAlive() ) {
|
||||
_interruptCore = isrCore;
|
||||
if(isrCore != CoreCurrent) {
|
||||
ESP_ERROR_CHECK(esp_ipc_call_blocking(isrCore, registerInterrupt, NULL));
|
||||
} else {
|
||||
registerInterrupt(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
ledForChannel( channel ) = this;
|
||||
}
|
||||
|
||||
~SmartLed() {
|
||||
ledForChannel( _channel ) = nullptr;
|
||||
if ( !anyAlive() ) {
|
||||
if(_interruptCore != CoreCurrent) {
|
||||
ESP_ERROR_CHECK(esp_ipc_call_blocking(_interruptCore, unregisterInterrupt, NULL));
|
||||
} else {
|
||||
unregisterInterrupt(NULL);
|
||||
}
|
||||
}
|
||||
vSemaphoreDelete( _finishedFlag );
|
||||
}
|
||||
|
||||
Rgb& operator[]( int idx ) {
|
||||
return _firstBuffer[ idx ];
|
||||
}
|
||||
|
||||
const Rgb& operator[]( int idx ) const {
|
||||
return _firstBuffer[ idx ];
|
||||
}
|
||||
|
||||
void show() {
|
||||
_buffer = _firstBuffer.get();
|
||||
startTransmission();
|
||||
swapBuffers();
|
||||
}
|
||||
|
||||
bool wait( TickType_t timeout = portMAX_DELAY ) {
|
||||
if( xSemaphoreTake( _finishedFlag, timeout ) == pdTRUE ) {
|
||||
xSemaphoreGive( _finishedFlag );
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int size() const {
|
||||
return _count;
|
||||
}
|
||||
|
||||
Rgb *begin() { return _firstBuffer.get(); }
|
||||
const Rgb *begin() const { return _firstBuffer.get(); }
|
||||
const Rgb *cbegin() const { return _firstBuffer.get(); }
|
||||
|
||||
Rgb *end() { return _firstBuffer.get() + _count; }
|
||||
const Rgb *end() const { return _firstBuffer.get() + _count; }
|
||||
const Rgb *cend() const { return _firstBuffer.get() + _count; }
|
||||
|
||||
private:
|
||||
static intr_handle_t _interruptHandle;
|
||||
static IsrCore _interruptCore;
|
||||
|
||||
static void initChannel( int channel ) {
|
||||
RMT.apb_conf.fifo_mask = 1; //enable memory access, instead of FIFO mode.
|
||||
RMT.apb_conf.mem_tx_wrap_en = 1; //wrap around when hitting end of buffer
|
||||
RMT.conf_ch[ channel ].conf0.div_cnt = detail::DIVIDER;
|
||||
RMT.conf_ch[ channel ].conf0.mem_size = 1;
|
||||
RMT.conf_ch[ channel ].conf0.carrier_en = 0;
|
||||
RMT.conf_ch[ channel ].conf0.carrier_out_lv = 1;
|
||||
RMT.conf_ch[ channel ].conf0.mem_pd = 0;
|
||||
|
||||
RMT.conf_ch[ channel ].conf1.rx_en = 0;
|
||||
RMT.conf_ch[ channel ].conf1.mem_owner = 0;
|
||||
RMT.conf_ch[ channel ].conf1.tx_conti_mode = 0; //loop back mode.
|
||||
RMT.conf_ch[ channel ].conf1.ref_always_on = 1; // use apb clock: 80M
|
||||
RMT.conf_ch[ channel ].conf1.idle_out_en = 1;
|
||||
RMT.conf_ch[ channel ].conf1.idle_out_lv = 0;
|
||||
}
|
||||
|
||||
static void registerInterrupt(void *) {
|
||||
ESP_ERROR_CHECK(esp_intr_alloc( ETS_RMT_INTR_SOURCE, 0, interruptHandler, nullptr, &_interruptHandle));
|
||||
}
|
||||
|
||||
static void unregisterInterrupt(void*) {
|
||||
esp_intr_free( _interruptHandle );
|
||||
}
|
||||
|
||||
static SmartLed*& IRAM_ATTR ledForChannel( int channel );
|
||||
static void IRAM_ATTR interruptHandler( void* );
|
||||
|
||||
void IRAM_ATTR copyRmtHalfBlock();
|
||||
|
||||
void swapBuffers() {
|
||||
if ( _secondBuffer )
|
||||
_firstBuffer.swap( _secondBuffer );
|
||||
}
|
||||
|
||||
void startTransmission() {
|
||||
// Invalid use of the library
|
||||
if( xSemaphoreTake( _finishedFlag, 0 ) != pdTRUE )
|
||||
abort();
|
||||
|
||||
_pixelPosition = _componentPosition = _halfIdx = 0;
|
||||
copyRmtHalfBlock();
|
||||
if ( _pixelPosition < _count )
|
||||
copyRmtHalfBlock();
|
||||
|
||||
RMT.conf_ch[ _channel ].conf1.mem_rd_rst = 1;
|
||||
RMT.conf_ch[ _channel ].conf1.tx_start = 1;
|
||||
}
|
||||
|
||||
static bool anyAlive() {
|
||||
for ( int i = 0; i != 8; i++ )
|
||||
if ( ledForChannel( i ) != nullptr ) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
const LedType& _timing;
|
||||
int _channel;
|
||||
detail::RmtPulsePair _bitToRmt[ 2 ];
|
||||
int _count;
|
||||
std::unique_ptr< Rgb[] > _firstBuffer;
|
||||
std::unique_ptr< Rgb[] > _secondBuffer;
|
||||
Rgb *_buffer;
|
||||
|
||||
xSemaphoreHandle _finishedFlag;
|
||||
|
||||
int _pixelPosition;
|
||||
int _componentPosition;
|
||||
int _halfIdx;
|
||||
};
|
||||
|
||||
class Apa102 {
|
||||
public:
|
||||
struct ApaRgb {
|
||||
ApaRgb( uint8_t r = 0, uint8_t g = 0, uint32_t b = 0, uint32_t v = 0xFF )
|
||||
: v( 0xE0 | v ), b( b ), g( g ), r( r )
|
||||
{}
|
||||
|
||||
ApaRgb& operator=( const Rgb& o ) {
|
||||
r = o.r;
|
||||
g = o.g;
|
||||
b = o.b;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ApaRgb& operator=( const Hsv& o ) {
|
||||
*this = Rgb{ o };
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint8_t v, b, g, r;
|
||||
};
|
||||
|
||||
static const int FINAL_FRAME_SIZE = 4;
|
||||
static const int TRANS_COUNT = 2 + 8;
|
||||
|
||||
Apa102( int count, int clkpin, int datapin, BufferType doubleBuffer = SingleBuffer )
|
||||
: _count( count ),
|
||||
_firstBuffer( new ApaRgb[ count ] ),
|
||||
_secondBuffer( doubleBuffer ? new ApaRgb[ count ] : nullptr ),
|
||||
_initFrame( 0 )
|
||||
{
|
||||
spi_bus_config_t buscfg;
|
||||
memset( &buscfg, 0, sizeof( buscfg ) );
|
||||
buscfg.mosi_io_num = datapin;
|
||||
buscfg.miso_io_num = -1;
|
||||
buscfg.sclk_io_num = clkpin;
|
||||
buscfg.quadwp_io_num = -1;
|
||||
buscfg.quadhd_io_num = -1;
|
||||
buscfg.max_transfer_sz = 65535;
|
||||
|
||||
spi_device_interface_config_t devcfg;
|
||||
memset( &devcfg, 0, sizeof( devcfg ) );
|
||||
devcfg.clock_speed_hz = 1000000;
|
||||
devcfg.mode = 0;
|
||||
devcfg.spics_io_num = -1;
|
||||
devcfg.queue_size = TRANS_COUNT;
|
||||
devcfg.pre_cb = nullptr;
|
||||
|
||||
auto ret = spi_bus_initialize( HSPI_HOST, &buscfg, 1 );
|
||||
assert( ret == ESP_OK );
|
||||
|
||||
ret = spi_bus_add_device( HSPI_HOST, &devcfg, &_spi );
|
||||
assert( ret == ESP_OK );
|
||||
|
||||
std::fill_n( _finalFrame, FINAL_FRAME_SIZE, 0xFFFFFFFF );
|
||||
}
|
||||
|
||||
~Apa102() {
|
||||
// ToDo
|
||||
}
|
||||
|
||||
ApaRgb& operator[]( int idx ) {
|
||||
return _firstBuffer[ idx ];
|
||||
}
|
||||
|
||||
const ApaRgb& operator[]( int idx ) const {
|
||||
return _firstBuffer[ idx ];
|
||||
}
|
||||
|
||||
void show() {
|
||||
_buffer = _firstBuffer.get();
|
||||
startTransmission();
|
||||
swapBuffers();
|
||||
}
|
||||
|
||||
void wait() {
|
||||
for ( int i = 0; i != _transCount; i++ ) {
|
||||
spi_transaction_t *t;
|
||||
spi_device_get_trans_result( _spi, &t, portMAX_DELAY );
|
||||
}
|
||||
}
|
||||
private:
|
||||
void swapBuffers() {
|
||||
if ( _secondBuffer )
|
||||
_firstBuffer.swap( _secondBuffer );
|
||||
}
|
||||
|
||||
void startTransmission() {
|
||||
for ( int i = 0; i != TRANS_COUNT; i++ ) {
|
||||
_transactions[ i ].cmd = 0;
|
||||
_transactions[ i ].addr = 0;
|
||||
_transactions[ i ].flags = 0;
|
||||
_transactions[ i ].rxlength = 0;
|
||||
_transactions[ i ].rx_buffer = nullptr;
|
||||
}
|
||||
// Init frame
|
||||
_transactions[ 0 ].length = 32;
|
||||
_transactions[ 0 ].tx_buffer = &_initFrame;
|
||||
spi_device_queue_trans( _spi, _transactions + 0, portMAX_DELAY );
|
||||
// Data
|
||||
_transactions[ 1 ].length = 32 * _count;
|
||||
_transactions[ 1 ].tx_buffer = _buffer;
|
||||
spi_device_queue_trans( _spi, _transactions + 1, portMAX_DELAY );
|
||||
_transCount = 2;
|
||||
// End frame
|
||||
for ( int i = 0; i != 1 + _count / 32 / FINAL_FRAME_SIZE; i++ ) {
|
||||
_transactions[ 2 + i ].length = 32 * FINAL_FRAME_SIZE;
|
||||
_transactions[ 2 + i ].tx_buffer = _finalFrame;
|
||||
spi_device_queue_trans( _spi, _transactions + 2 + i, portMAX_DELAY );
|
||||
_transCount++;
|
||||
}
|
||||
}
|
||||
|
||||
spi_device_handle_t _spi;
|
||||
int _count;
|
||||
std::unique_ptr< ApaRgb[] > _firstBuffer, _secondBuffer;
|
||||
ApaRgb *_buffer;
|
||||
|
||||
spi_transaction_t _transactions[ TRANS_COUNT ];
|
||||
int _transCount;
|
||||
|
||||
uint32_t _initFrame;
|
||||
uint32_t _finalFrame[ FINAL_FRAME_SIZE ];
|
||||
};
|
||||
|
||||
class LDP8806 {
|
||||
public:
|
||||
struct LDP8806_GRB {
|
||||
|
||||
LDP8806_GRB( uint8_t g_7bit = 0, uint8_t r_7bit = 0, uint32_t b_7bit = 0 )
|
||||
: g( g_7bit ), r( r_7bit ), b( b_7bit )
|
||||
{
|
||||
}
|
||||
|
||||
LDP8806_GRB& operator=( const Rgb& o ) {
|
||||
//Convert 8->7bit colour
|
||||
r = ( o.r * 127 / 256 ) | 0x80;
|
||||
g = ( o.g * 127 / 256 ) | 0x80;
|
||||
b = ( o.b * 127 / 256 ) | 0x80;
|
||||
return *this;
|
||||
}
|
||||
|
||||
LDP8806_GRB& operator=( const Hsv& o ) {
|
||||
*this = Rgb{ o };
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint8_t g, r, b;
|
||||
};
|
||||
|
||||
static const int LED_FRAME_SIZE_BYTES = sizeof( LDP8806_GRB );
|
||||
static const int LATCH_FRAME_SIZE_BYTES = 3;
|
||||
static const int TRANS_COUNT_MAX = 20;//Arbitrary, supports up to 600 LED
|
||||
|
||||
LDP8806( int count, int clkpin, int datapin, BufferType doubleBuffer = SingleBuffer, uint32_t clock_speed_hz = 2000000 )
|
||||
: _count( count ),
|
||||
_firstBuffer( new LDP8806_GRB[ count ] ),
|
||||
_secondBuffer( doubleBuffer ? new LDP8806_GRB[ count ] : nullptr ),
|
||||
// one 'latch'/start-of-data mark frame for every 32 leds
|
||||
_latchFrames( ( count + 31 ) / 32 )
|
||||
{
|
||||
spi_bus_config_t buscfg;
|
||||
memset( &buscfg, 0, sizeof( buscfg ) );
|
||||
buscfg.mosi_io_num = datapin;
|
||||
buscfg.miso_io_num = -1;
|
||||
buscfg.sclk_io_num = clkpin;
|
||||
buscfg.quadwp_io_num = -1;
|
||||
buscfg.quadhd_io_num = -1;
|
||||
buscfg.max_transfer_sz = 65535;
|
||||
|
||||
spi_device_interface_config_t devcfg;
|
||||
memset( &devcfg, 0, sizeof( devcfg ) );
|
||||
devcfg.clock_speed_hz = clock_speed_hz;
|
||||
devcfg.mode = 0;
|
||||
devcfg.spics_io_num = -1;
|
||||
devcfg.queue_size = TRANS_COUNT_MAX;
|
||||
devcfg.pre_cb = nullptr;
|
||||
|
||||
auto ret = spi_bus_initialize( HSPI_HOST, &buscfg, 1 );
|
||||
assert( ret == ESP_OK );
|
||||
|
||||
ret = spi_bus_add_device( HSPI_HOST, &devcfg, &_spi );
|
||||
assert( ret == ESP_OK );
|
||||
|
||||
std::fill_n( _latchBuffer, LATCH_FRAME_SIZE_BYTES, 0x0 );
|
||||
}
|
||||
|
||||
~LDP8806() {
|
||||
// noop
|
||||
}
|
||||
|
||||
LDP8806_GRB& operator[]( int idx ) {
|
||||
return _firstBuffer[ idx ];
|
||||
}
|
||||
|
||||
const LDP8806_GRB& operator[]( int idx ) const {
|
||||
return _firstBuffer[ idx ];
|
||||
}
|
||||
|
||||
void show() {
|
||||
_buffer = _firstBuffer.get();
|
||||
startTransmission();
|
||||
swapBuffers();
|
||||
}
|
||||
|
||||
void wait() {
|
||||
while ( _transCount-- ) {
|
||||
spi_transaction_t *t;
|
||||
spi_device_get_trans_result( _spi, &t, portMAX_DELAY );
|
||||
}
|
||||
}
|
||||
private:
|
||||
void swapBuffers() {
|
||||
if ( _secondBuffer )
|
||||
_firstBuffer.swap( _secondBuffer );
|
||||
}
|
||||
|
||||
void startTransmission() {
|
||||
_transCount = 0;
|
||||
for ( int i = 0; i != TRANS_COUNT_MAX; i++ ) {
|
||||
_transactions[ i ].cmd = 0;
|
||||
_transactions[ i ].addr = 0;
|
||||
_transactions[ i ].flags = 0;
|
||||
_transactions[ i ].rxlength = 0;
|
||||
_transactions[ i ].rx_buffer = nullptr;
|
||||
}
|
||||
// LED Data
|
||||
_transactions[ 0 ].length = ( LED_FRAME_SIZE_BYTES * 8 ) * _count;
|
||||
_transactions[ 0 ].tx_buffer = _buffer;
|
||||
spi_device_queue_trans( _spi, _transactions + _transCount, portMAX_DELAY );
|
||||
_transCount++;
|
||||
|
||||
// 'latch'/start-of-data marker frames
|
||||
for ( int i = 0; i < _latchFrames; i++ ) {
|
||||
_transactions[ _transCount ].length = ( LATCH_FRAME_SIZE_BYTES * 8 );
|
||||
_transactions[ _transCount ].tx_buffer = _latchBuffer;
|
||||
spi_device_queue_trans( _spi, _transactions + _transCount, portMAX_DELAY );
|
||||
_transCount++;
|
||||
}
|
||||
}
|
||||
|
||||
spi_device_handle_t _spi;
|
||||
int _count;
|
||||
std::unique_ptr< LDP8806_GRB[] > _firstBuffer, _secondBuffer;
|
||||
LDP8806_GRB *_buffer;
|
||||
|
||||
spi_transaction_t _transactions[ TRANS_COUNT_MAX ];
|
||||
int _transCount;
|
||||
|
||||
int _latchFrames;
|
||||
uint8_t _latchBuffer[ LATCH_FRAME_SIZE_BYTES ];
|
||||
};
|
||||
@@ -142,13 +142,7 @@ void task_NoSDBlink(void *pvParameter)
|
||||
extern "C" void app_main(void)
|
||||
{
|
||||
TickType_t xDelay;
|
||||
|
||||
|
||||
printf("Do Reset Camera\n");
|
||||
PowerResetCamera();
|
||||
Camera.InitCam();
|
||||
Camera.LightOnOff(false);
|
||||
|
||||
|
||||
if (!Init_NVS_SDCard())
|
||||
{
|
||||
xTaskCreate(&task_NoSDBlink, "task_NoSDBlink", configMINIMAL_STACK_SIZE * 64, NULL, tskIDLE_PRIORITY+1, NULL);
|
||||
@@ -176,8 +170,8 @@ extern "C" void app_main(void)
|
||||
printf("DNS IP: %s\n", dns);
|
||||
|
||||
|
||||
wifi_init_sta(ssid, passwd, hostname, ip, gateway, netmask, dns);
|
||||
|
||||
wifi_init_sta(ssid, passwd, hostname, ip, gateway, netmask, dns);
|
||||
|
||||
|
||||
xDelay = 2000 / portTICK_PERIOD_MS;
|
||||
printf("main: sleep for : %ldms\n", (long) xDelay);
|
||||
@@ -198,8 +192,8 @@ extern "C" void app_main(void)
|
||||
printf("time %s\n", zw.c_str());
|
||||
|
||||
// Camera.InitCam();
|
||||
// Camera.LightOnOff(false);
|
||||
xDelay = 2000 / portTICK_PERIOD_MS;
|
||||
// Camera.LightOnOff(false);
|
||||
xDelay = 2000 / portTICK_PERIOD_MS;
|
||||
printf("main: sleep for : %ldms\n", (long) xDelay);
|
||||
vTaskDelay( xDelay );
|
||||
|
||||
@@ -215,6 +209,22 @@ extern "C" void app_main(void)
|
||||
register_server_main_uri(server, "/sdcard");
|
||||
|
||||
printf("vor dotautostart\n");
|
||||
TFliteDoAutoStart();
|
||||
|
||||
// init camera module
|
||||
printf("Do Reset Camera\n");
|
||||
PowerResetCamera();
|
||||
esp_err_t cam = Camera.InitCam();
|
||||
if (cam != ESP_OK) {
|
||||
ESP_LOGE(TAGMAIN, "Failed to initialize camera module. "
|
||||
"Check that your camera module is working and connected properly.");
|
||||
|
||||
LogFile.SwitchOnOff(true);
|
||||
LogFile.WriteToFile("Failed to initialize camera module. "
|
||||
"Check that your camera module is working and connected properly.");
|
||||
LogFile.SwitchOnOff(false);
|
||||
} else {
|
||||
Camera.LightOnOff(false);
|
||||
TFliteDoAutoStart();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const char* GIT_REV="d0bf12f";
|
||||
const char* GIT_REV="e22b4b6";
|
||||
const char* GIT_TAG="";
|
||||
const char* GIT_BRANCH="master";
|
||||
const char* BUILD_TIME="2021-10-07 07:17";
|
||||
const char* BUILD_TIME="2021-12-02 21:53";
|
||||
@@ -13,7 +13,7 @@ extern "C"
|
||||
#include "Helper.h"
|
||||
#include <fstream>
|
||||
|
||||
const char* GIT_BASE_BRANCH = "master - v8.5.0 - 2021-10-07";
|
||||
const char* GIT_BASE_BRANCH = "master - v9.2.0 - 2021-12-02";
|
||||
|
||||
|
||||
const char* git_base_branch(void)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const char* GIT_REV="d0bf12f";
|
||||
const char* GIT_REV="e22b4b6";
|
||||
const char* GIT_TAG="";
|
||||
const char* GIT_BRANCH="master";
|
||||
const char* BUILD_TIME="2021-10-07 07:17";
|
||||
const char* BUILD_TIME="2021-12-02 21:53";
|
||||
BIN
images/Power_Meter_Mounted.jpg
Normal file
|
After Width: | Height: | Size: 438 KiB |
|
Before Width: | Height: | Size: 140 KiB After Width: | Height: | Size: 140 KiB |
BIN
images/config_s5_ROIs_details.jpg
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
images/external_GPIO_settings.jpg
Normal file
|
After Width: | Height: | Size: 56 KiB |
BIN
images/install_external_led.jpg
Normal file
|
After Width: | Height: | Size: 119 KiB |
BIN
images/intern_vs_external.jpg
Normal file
|
After Width: | Height: | Size: 71 KiB |
BIN
images/ota-update-details.jpg
Normal file
|
After Width: | Height: | Size: 106 KiB |
BIN
images/ota-update-menue.jpg
Normal file
|
After Width: | Height: | Size: 65 KiB |
BIN
sd-card/config/ana0910s3_longq.tflite
Normal file
@@ -20,7 +20,7 @@ FlipImageSize = false
|
||||
/config/ref1.jpg 442 142
|
||||
|
||||
[Digits]
|
||||
Model = /config/dig1310s3q.tflite
|
||||
Model = /config/dig1330s1q.tflite
|
||||
;LogImageLocation = /log/digit
|
||||
;LogfileRetentionInDays = 3
|
||||
ModelInputSize = 20 32
|
||||
@@ -29,7 +29,7 @@ main.dig2 343 126 30 54
|
||||
main.dig3 391 126 30 54
|
||||
|
||||
[Analog]
|
||||
Model = /config/ana0700s1lq.tflite
|
||||
Model = /config/ana0910s3_longq.tflite
|
||||
;LogImageLocation = /log/analog
|
||||
;LogfileRetentionInDays = 3
|
||||
ModelInputSize = 32 32
|
||||
@@ -46,7 +46,7 @@ PreValueAgeStartup = 720
|
||||
AllowNegativeRates = false
|
||||
main.MaxRateValue = 0.1
|
||||
ErrorMessage = true
|
||||
CheckDigitIncreaseConsistency = true
|
||||
CheckDigitIncreaseConsistency = false
|
||||
|
||||
;[MQTT]
|
||||
;Uri = mqtt://IP-ADRESS:1883
|
||||
@@ -62,7 +62,10 @@ CheckDigitIncreaseConsistency = true
|
||||
;IO3 = input disabled 10 false false
|
||||
;IO4 = built-in-led disabled 10 false false
|
||||
;IO12 = input-pullup disabled 10 false false
|
||||
;IO13 = input-pullup disabled 10 false false
|
||||
;IO13 = input-pullup disabled 10 false false
|
||||
LEDType = WS2812
|
||||
LEDNumbers = 2
|
||||
LEDColor = 50 50 50
|
||||
|
||||
[AutoTimer]
|
||||
AutoStart = true
|
||||
|
||||
BIN
sd-card/config/dig1330s1q.tflite
Normal file
@@ -636,13 +636,13 @@ textarea {
|
||||
<td colspan="4" style="padding-left: 20px;">
|
||||
<h4><input type="checkbox" id="Category_GPIO_enabled" value="1" onclick='UpdateAfterCategoryCheck()' unchecked >
|
||||
GPIO Settings
|
||||
<span class="GPIO_item" style="color: red;"><b>EXPERIMENTAL</b> - Enabling GPIO handler, disable by default integrated flash light. Please enable it with GPIO4 settings.</span>
|
||||
<span class="GPIO_item" > - Enabling GPIO handler, disable by default integrated flash light. Please enable it with GPIO4 (internal flash LED) settings or GPIO12 (external LED).</span>
|
||||
</h4>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!------------- GPIO0 begin ------------------>
|
||||
<tr class="GPIO_IO0 GPIO_item">
|
||||
<tr class="expert" class="GPIO_IO0 GPIO_item">
|
||||
<td width="20px" style="padding-left: 40px;">
|
||||
<input type="checkbox" id="GPIO_IO0_enabled" value="1" onclick = 'InvertEnableItem("GPIO", "IO0")' unchecked>
|
||||
</td>
|
||||
@@ -656,9 +656,6 @@ textarea {
|
||||
<option value="input-pullup">input pullup</option>
|
||||
<option value="input-pulldown">input pulldown</option>
|
||||
<option value="output">output</option>
|
||||
<option value="output-pwm" disabled>output pwm (not implemented)</option>
|
||||
<option value="external-flash-pwm" disabled>external flash light pwm controlled (not implemented)</option>
|
||||
<option value="external-flash-ws281x" disabled>external flash light ws281x controlled (not implemented)</option>
|
||||
</select>
|
||||
</td>
|
||||
</td>
|
||||
@@ -668,10 +665,10 @@ textarea {
|
||||
<span style="color: red">Pin is used to activate flash mode and must therefore be HIGH when booting.</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="GPIO_IO0 GPIO_item">
|
||||
<tr class="expert" class="GPIO_IO0 GPIO_item">
|
||||
<td width="20px" style="padding-left: 40px;"></td>
|
||||
<td>
|
||||
<span>GPIO 0 use interrupt</span>
|
||||
<span id="GPIO_IO0_text" class="GPIO_IO0 GPIO_item">GPIO 0 use interrupt</span>
|
||||
</td>
|
||||
<td>
|
||||
<td">
|
||||
@@ -689,10 +686,10 @@ textarea {
|
||||
GPIO 0 enable interrupt trigger
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="GPIO_IO0 GPIO_item">
|
||||
<tr class="expert" class="GPIO_IO0 GPIO_item">
|
||||
<td width="20px" style="padding-left: 40px;"></td>
|
||||
<td>
|
||||
<span>GPIO 0 PWM duty resolution</span>
|
||||
<span class="GPIO_IO0 GPIO_item">GPIO 0 PWM duty resolution</span>
|
||||
</td>
|
||||
<td>
|
||||
<td"><input type="number" id="GPIO_IO0_value3" min="1" max="20"></td>
|
||||
@@ -701,10 +698,10 @@ textarea {
|
||||
GPIO 0 LEDC PWM duty resolution in bit
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="GPIO_IO0 GPIO_item">
|
||||
<tr class="expert" class="GPIO_IO0 GPIO_item">
|
||||
<td width="20px" style="padding-left: 40px;"></td>
|
||||
<td>
|
||||
<span>GPIO 0 enable MQTT</span>
|
||||
<span class="GPIO_IO0 GPIO_item">GPIO 0 enable MQTT</span>
|
||||
</td>
|
||||
<td>
|
||||
<td"><input type="checkbox" id="GPIO_IO0_value4"></td>
|
||||
@@ -713,10 +710,10 @@ textarea {
|
||||
GPIO 0 enable MQTT publishing/subscribing
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="GPIO_IO0 GPIO_item">
|
||||
<tr class="expert" class="GPIO_IO0 GPIO_item">
|
||||
<td width="20px" style="padding-left: 40px;"></td>
|
||||
<td>
|
||||
<span>GPIO 0 enable HTTP</span>
|
||||
<span class="GPIO_IO0 GPIO_item">GPIO 0 enable HTTP</span>
|
||||
</td>
|
||||
<td>
|
||||
<td"><input type="checkbox" id="GPIO_IO0_value5"></td>
|
||||
@@ -725,10 +722,10 @@ textarea {
|
||||
GPIO 0 enable HTTP write/read
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="GPIO_IO0 GPIO_item">
|
||||
<tr class="expert" class="GPIO_IO0 GPIO_item">
|
||||
<td width="20px" style="padding-left: 40px;"></td>
|
||||
<td>
|
||||
<span>GPIO 0 name</span>
|
||||
<span class="GPIO_IO0 GPIO_item">GPIO 0 name</span>
|
||||
</td>
|
||||
<td>
|
||||
<td"><input type="text" id="GPIO_IO0_value6"></td>
|
||||
@@ -740,12 +737,12 @@ textarea {
|
||||
<!------------- GPIO0 end ------------------>
|
||||
|
||||
<!------------- GPIO1 begin ------------------>
|
||||
<tr class="GPIO_IO1 GPIO_item">
|
||||
<tr class="expert" class="GPIO_IO1 GPIO_item">
|
||||
<td width="20px" style="padding-left: 40px;">
|
||||
<input type="checkbox" id="GPIO_IO1_enabled" value="1" onclick = 'InvertEnableItem("GPIO", "IO1")' unchecked>
|
||||
</td>
|
||||
<td>
|
||||
<span id="GPIO_IO1_text">GPIO 1 state</span>
|
||||
<span id="GPIO_IO1_text" class="GPIO_IO1 GPIO_item">GPIO 1 state</span>
|
||||
</td>
|
||||
<td>
|
||||
<td">
|
||||
@@ -754,9 +751,6 @@ textarea {
|
||||
<option value="input-pullup">input pullup</option>
|
||||
<option value="input-pulldown">input pulldown</option>
|
||||
<option value="output">output</option>
|
||||
<option value="output-pwm" disabled>output pwm (not implemented)</option>
|
||||
<option value="external-flash-pwm" disabled>external flash light pwm controlled (not implemented)</option>
|
||||
<option value="external-flash-ws281x" disabled>external flash light ws281x controlled (not implemented)</option>
|
||||
</select>
|
||||
</td>
|
||||
</td>
|
||||
@@ -764,10 +758,10 @@ textarea {
|
||||
GPIO 1 <br><span style="color: blue">Used by default for serial communication as TX pin.<br>Required for seriales monitor.</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="GPIO_IO1 GPIO_item">
|
||||
<tr class="expert" class="GPIO_IO1 GPIO_item">
|
||||
<td width="20px" style="padding-left: 40px;"></td>
|
||||
<td>
|
||||
<span>GPIO 1 use interrupt</span>
|
||||
<span class="GPIO_IO1 GPIO_item" class="expert">GPIO 1 use interrupt</span>
|
||||
</td>
|
||||
<td>
|
||||
<td">
|
||||
@@ -785,10 +779,10 @@ textarea {
|
||||
GPIO 1 enable interrupt trigger
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="GPIO_IO1 GPIO_item">
|
||||
<tr class="expert" class="GPIO_IO1 GPIO_item">
|
||||
<td width="20px" style="padding-left: 40px;"></td>
|
||||
<td>
|
||||
<span>GPIO 1 PWM duty resolution</span>
|
||||
<span class="GPIO_IO1 GPIO_item">GPIO 1 PWM duty resolution</span>
|
||||
</td>
|
||||
<td>
|
||||
<td"><input type="number" id="GPIO_IO1_value3" min="1" max="20"></td>
|
||||
@@ -797,10 +791,10 @@ textarea {
|
||||
GPIO 1 LEDC PWM duty resolution in bit
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="GPIO_IO1 GPIO_item">
|
||||
<tr class="expert" class="GPIO_IO1 GPIO_item">
|
||||
<td width="20px" style="padding-left: 40px;"></td>
|
||||
<td>
|
||||
<span>GPIO 1 enable MQTT</span>
|
||||
<span class="GPIO_IO1 GPIO_item">GPIO 1 enable MQTT</span>
|
||||
</td>
|
||||
<td>
|
||||
<td"><input type="checkbox" id="GPIO_IO1_value4"></td>
|
||||
@@ -809,10 +803,10 @@ textarea {
|
||||
GPIO 1 enable MQTT publishing/subscribing
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="GPIO_IO1 GPIO_item">
|
||||
<tr class="expert" class="GPIO_IO1 GPIO_item">
|
||||
<td width="20px" style="padding-left: 40px;"></td>
|
||||
<td>
|
||||
<span>GPIO 1 enable HTTP</span>
|
||||
<span class="GPIO_IO1 GPIO_item">GPIO 1 enable HTTP</span>
|
||||
</td>
|
||||
<td>
|
||||
<td"><input type="checkbox" id="GPIO_IO1_value5"></td>
|
||||
@@ -821,10 +815,10 @@ textarea {
|
||||
GPIO 1 enable HTTP write/read
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="GPIO_IO1 GPIO_item">
|
||||
<tr class="expert" class="GPIO_IO1 GPIO_item">
|
||||
<td width="20px" style="padding-left: 40px;"></td>
|
||||
<td>
|
||||
<span>GPIO 1 name</span>
|
||||
<span class="GPIO_IO1 GPIO_item" class="expert">GPIO 1 name</span>
|
||||
</td>
|
||||
<td>
|
||||
<td"><input type="text" id="GPIO_IO1_value6"></td>
|
||||
@@ -836,12 +830,12 @@ textarea {
|
||||
<!------------- GPIO1 end ------------------>
|
||||
|
||||
<!------------- GPIO3 begin ------------------>
|
||||
<tr class="GPIO_IO3 GPIO_item">
|
||||
<tr class="expert" class="GPIO_IO3 GPIO_item">
|
||||
<td width="20px" style="padding-left: 40px;">
|
||||
<input type="checkbox" id="GPIO_IO3_enabled" value="1" onclick = 'InvertEnableItem("GPIO", "IO3")' unchecked>
|
||||
</td>
|
||||
<td>
|
||||
<span id="GPIO_IO3_text">GPIO 3 state</span>
|
||||
<span id="GPIO_IO3_text" class="GPIO_IO3 GPIO_item">GPIO 3 state</span>
|
||||
</td>
|
||||
<td>
|
||||
<td">
|
||||
@@ -850,9 +844,6 @@ textarea {
|
||||
<option value="input-pullup">input pullup</option>
|
||||
<option value="input-pulldown">input pulldown</option>
|
||||
<option value="output">output</option>
|
||||
<option value="output-pwm" disabled>output pwm (not implemented)</option>
|
||||
<option value="external-flash-pwm" disabled>external flash light pwm controlled (not implemented)</option>
|
||||
<option value="external-flash-ws281x" disabled>external flash light ws281x controlled (not implemented)</option>
|
||||
</select>
|
||||
</td>
|
||||
</td>
|
||||
@@ -860,10 +851,10 @@ textarea {
|
||||
GPIO 3 <span style="color: blue">Used by default for serial communication as RX pin.</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="GPIO_IO3 GPIO_item">
|
||||
<tr class="expert" class="GPIO_IO3 GPIO_item">
|
||||
<td width="20px" style="padding-left: 40px;"></td>
|
||||
<td>
|
||||
<span>GPIO 3 use interrupt</span>
|
||||
<span class="GPIO_IO3 GPIO_item">GPIO 3 use interrupt</span>
|
||||
</td>
|
||||
<td>
|
||||
<td">
|
||||
@@ -881,10 +872,10 @@ textarea {
|
||||
GPIO 3 Used by default for serial communication as RX pin.
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="GPIO_IO3 GPIO_item">
|
||||
<tr class="expert" class="GPIO_IO3 GPIO_item">
|
||||
<td width="20px" style="padding-left: 40px;"></td>
|
||||
<td>
|
||||
<span>GPIO 3 PWM duty resolution</span>
|
||||
<span class="GPIO_IO3 GPIO_item">GPIO 3 PWM duty resolution</span>
|
||||
</td>
|
||||
<td>
|
||||
<td"><input type="number" id="GPIO_IO3_value3" min="1" max="20"></td>
|
||||
@@ -893,10 +884,10 @@ textarea {
|
||||
GPIO 3 LEDC PWM duty resolution in bit
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="GPIO_IO3 GPIO_item">
|
||||
<tr class="expert" class="GPIO_IO3 GPIO_item">
|
||||
<td width="20px" style="padding-left: 40px;"></td>
|
||||
<td>
|
||||
<span>GPIO 3 enable MQTT</span>
|
||||
<span class="GPIO_IO3 GPIO_item">GPIO 3 enable MQTT</span>
|
||||
</td>
|
||||
<td>
|
||||
<td"><input type="checkbox" id="GPIO_IO3_value4"></td>
|
||||
@@ -905,10 +896,10 @@ textarea {
|
||||
GPIO 3 enable MQTT publishing/subscribing
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="GPIO_IO3 GPIO_item">
|
||||
<tr class="expert" class="GPIO_IO3 GPIO_item">
|
||||
<td width="20px" style="padding-left: 40px;"></td>
|
||||
<td>
|
||||
<span>GPIO 3 enable HTTP</span>
|
||||
<span class="GPIO_IO3 GPIO_item">GPIO 3 enable HTTP</span>
|
||||
</td>
|
||||
<td>
|
||||
<td"><input type="checkbox" id="GPIO_IO3_value5"></td>
|
||||
@@ -917,10 +908,10 @@ textarea {
|
||||
GPIO 3 enable HTTP write/read
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="GPIO_IO3 GPIO_item">
|
||||
<tr class="expert" class="GPIO_IO3 GPIO_item">
|
||||
<td width="20px" style="padding-left: 40px;"></td>
|
||||
<td>
|
||||
<span>GPIO 3 name</span>
|
||||
<span class="GPIO_IO3 GPIO_item">GPIO 3 name</span>
|
||||
</td>
|
||||
<td>
|
||||
<td"><input type="text" id="GPIO_IO3_value6"></td>
|
||||
@@ -937,7 +928,7 @@ textarea {
|
||||
<input type="checkbox" id="GPIO_IO4_enabled" value="1" onclick = 'InvertEnableItem("GPIO", "IO4")' unchecked>
|
||||
</td>
|
||||
<td>
|
||||
<span id="GPIO_IO4_text">GPIO 4 state</span>
|
||||
<span id="GPIO_IO4_text" class="GPIO_IO4 GPIO_item">GPIO 4 state</span>
|
||||
</td>
|
||||
<td>
|
||||
<td">
|
||||
@@ -947,9 +938,6 @@ textarea {
|
||||
<option value="input-pulldown">input pulldown</option>
|
||||
<option value="output">output</option>
|
||||
<option value="built-in-led">built-in led flash light</option>
|
||||
<option value="output-pwm" disabled>output pwm (not implemented)</option>
|
||||
<option value="external-flash-pwm" disabled>external flash light pwm controlled (not implemented)</option>
|
||||
<option value="external-flash-ws281x" disabled>external flash light ws281x controlled (not implemented)</option>
|
||||
</select>
|
||||
</td>
|
||||
</td>
|
||||
@@ -958,10 +946,10 @@ textarea {
|
||||
<span style="color: red">Pin is used for build-in flash light.</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="GPIO_IO4 GPIO_item">
|
||||
<tr class="expert" class="GPIO_IO4 GPIO_item">
|
||||
<td width="20px" style="padding-left: 40px;"></td>
|
||||
<td>
|
||||
<span>GPIO 4 use interrupt</span>
|
||||
<span class="GPIO_IO4 GPIO_item">GPIO 4 use interrupt</span>
|
||||
</td>
|
||||
<td>
|
||||
<td">
|
||||
@@ -979,10 +967,10 @@ textarea {
|
||||
GPIO 4 enable interrupt trigger
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="GPIO_IO4 GPIO_item">
|
||||
<tr class="expert" class="GPIO_IO4 GPIO_item">
|
||||
<td width="20px" style="padding-left: 40px;"></td>
|
||||
<td>
|
||||
<span>GPIO 4 PWM duty resolution</span>
|
||||
<span class="GPIO_IO4 GPIO_item">GPIO 4 PWM duty resolution</span>
|
||||
</td>
|
||||
<td>
|
||||
<td"><input type="number" id="GPIO_IO4_value3" min="1" max="20"></td>
|
||||
@@ -991,10 +979,10 @@ textarea {
|
||||
GPIO 4 LEDC PWM duty resolution in bit
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="GPIO_IO4 GPIO_item">
|
||||
<tr class="expert" class="GPIO_IO4 GPIO_item">
|
||||
<td width="20px" style="padding-left: 40px;"></td>
|
||||
<td>
|
||||
<span>GPIO 4 enable MQTT</span>
|
||||
<span class="GPIO_IO4 GPIO_item">GPIO 4 enable MQTT</span>
|
||||
</td>
|
||||
<td>
|
||||
<td"><input type="checkbox" id="GPIO_IO4_value4"></td>
|
||||
@@ -1003,10 +991,10 @@ textarea {
|
||||
GPIO 4 enable MQTT publishing/subscribing
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="GPIO_IO4 GPIO_item">
|
||||
<tr class="expert" class="GPIO_IO4 GPIO_item">
|
||||
<td width="20px" style="padding-left: 40px;"></td>
|
||||
<td>
|
||||
<span>GPIO 4 enable HTTP</span>
|
||||
<span class="GPIO_IO4 GPIO_item">GPIO 4 enable HTTP</span>
|
||||
</td>
|
||||
<td>
|
||||
<td"><input type="checkbox" id="GPIO_IO4_value5"></td>
|
||||
@@ -1015,10 +1003,10 @@ textarea {
|
||||
GPIO 4 enable HTTP write/read
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="GPIO_IO4 GPIO_item">
|
||||
<tr class="expert" class="GPIO_IO4 GPIO_item">
|
||||
<td width="20px" style="padding-left: 40px;"></td>
|
||||
<td>
|
||||
<span>GPIO 4 name</span>
|
||||
<span class="GPIO_IO4 GPIO_item">GPIO 4 name</span>
|
||||
</td>
|
||||
<td>
|
||||
<td"><input type="text" id="GPIO_IO4_value6"></td>
|
||||
@@ -1035,7 +1023,7 @@ textarea {
|
||||
<input type="checkbox" id="GPIO_IO12_enabled" value="1" onclick = 'InvertEnableItem("GPIO", "IO12")' unchecked>
|
||||
</td>
|
||||
<td>
|
||||
<span id="GPIO_IO12_text">GPIO 12 state</span>
|
||||
<span class="GPIO_IO12 GPIO_item" id="GPIO_IO12_text">GPIO 12 state</span>
|
||||
</td>
|
||||
<td>
|
||||
<td">
|
||||
@@ -1044,9 +1032,7 @@ textarea {
|
||||
<option value="input-pullup">input pullup</option>
|
||||
<option value="input-pulldown">input pulldown</option>
|
||||
<option value="output">output</option>
|
||||
<option value="output-pwm" disabled>output pwm (not implemented)</option>
|
||||
<option value="external-flash-pwm" disabled>external flash light pwm controlled (not implemented)</option>
|
||||
<option value="external-flash-ws281x">external flash light ws281x controlled (experimental)</option>
|
||||
<option value="external-flash-ws281x">external flash light ws281x controlled</option>
|
||||
</select>
|
||||
</td>
|
||||
</td>
|
||||
@@ -1054,14 +1040,14 @@ textarea {
|
||||
GPIO 12 is usable without restrictions
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="GPIO_IO12 GPIO_item">
|
||||
<tr class="expert" class="GPIO_IO12 GPIO_item">
|
||||
<td width="20px" style="padding-left: 40px;"></td>
|
||||
<td>
|
||||
<span>GPIO 12 use interrupt</span>
|
||||
<span class="GPIO_IO12 GPIO_item">GPIO 12 use interrupt</span>
|
||||
</td>
|
||||
<td>
|
||||
<td">
|
||||
<select id="GPIO_IO12_value2">
|
||||
<td>
|
||||
<select class="GPIO_IO12 GPIO_item" id="GPIO_IO12_value2">
|
||||
<option value="disabled">disabled</option>
|
||||
<option value="rising-edge">rising edge</option>
|
||||
<option value="falling-edge">falling edge</option>
|
||||
@@ -1075,10 +1061,10 @@ textarea {
|
||||
GPIO 12 enable interrupt trigger
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="GPIO_IO12 GPIO_item">
|
||||
<tr class="expert" class="GPIO_IO12 GPIO_item">
|
||||
<td width="20px" style="padding-left: 40px;"></td>
|
||||
<td>
|
||||
<span>GPIO 12 PWM duty resolution</span>
|
||||
<span class="GPIO_IO12 GPIO_item">GPIO 12 PWM duty resolution</span>
|
||||
</td>
|
||||
<td>
|
||||
<td"><input type="number" id="GPIO_IO12_value3" min="1" max="20"></td>
|
||||
@@ -1087,10 +1073,10 @@ textarea {
|
||||
GPIO 12 LEDC PWM duty resolution in bit
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="GPIO_IO12 GPIO_item">
|
||||
<tr class="expert" class="GPIO_IO12 GPIO_item">
|
||||
<td width="20px" style="padding-left: 40px;"></td>
|
||||
<td>
|
||||
<span>GPIO 12 enable MQTT</span>
|
||||
<span class="GPIO_IO12 GPIO_item">GPIO 12 enable MQTT</span>
|
||||
</td>
|
||||
<td>
|
||||
<td"><input type="checkbox" id="GPIO_IO12_value4"></td>
|
||||
@@ -1099,10 +1085,10 @@ textarea {
|
||||
GPIO 12 enable MQTT publishing/subscribing
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="GPIO_IO12 GPIO_item">
|
||||
<tr class="expert" class="GPIO_IO12 GPIO_item">
|
||||
<td width="20px" style="padding-left: 40px;"></td>
|
||||
<td>
|
||||
<span>GPIO 12 enable HTTP</span>
|
||||
<span class="GPIO_IO12 GPIO_item">GPIO 12 enable HTTP</span>
|
||||
</td>
|
||||
<td>
|
||||
<td"><input type="checkbox" id="GPIO_IO12_value5"></td>
|
||||
@@ -1111,10 +1097,10 @@ textarea {
|
||||
GPIO 12 enable HTTP write/read
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="GPIO_IO12 GPIO_item">
|
||||
<tr class="expert" class="GPIO_IO12 GPIO_item">
|
||||
<td width="20px" style="padding-left: 40px;"></td>
|
||||
<td>
|
||||
<span>GPIO 12 name</span>
|
||||
<span class="GPIO_IO12 GPIO_item">GPIO 12 name</span>
|
||||
</td>
|
||||
<td>
|
||||
<td"><input type="text" id="GPIO_IO12_value6"></td>
|
||||
@@ -1123,10 +1109,60 @@ textarea {
|
||||
GPIO 12 MQTT topic name (empty = GPIO12). Allowed characters (a-z, A-Z, 0-9, _, -)
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr class="GPIO_IO12 GPIO_item" id="wstypeex3">
|
||||
<td width="20px" style="padding-left: 40px;">
|
||||
</td>
|
||||
<td>
|
||||
<span class="GPIO_IO12 GPIO_item" id="GPIO_LEDType_text">LED-Type</span>
|
||||
</td>
|
||||
<td class="GPIO_IO12 GPIO_item">
|
||||
<select class="GPIO_IO12 GPIO_item" id="GPIO_LEDType_value1">
|
||||
<option value="WS2812" selected>WS2812</option>
|
||||
<option value="WS2812B">WS2812B</option>
|
||||
<option value="SK6812">SK6812 (not tested)</option>
|
||||
<option value="WS2813">WS2813 (not tested)</option>
|
||||
</select>
|
||||
</td>
|
||||
<td class="description">
|
||||
Type of WS2812x, that is connected to GPIO12
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr class="GPIO_IO12 GPIO_item" id="LEDANZex8" >
|
||||
<td width="20px" style="padding-left: 40px;">
|
||||
</td>
|
||||
<td>
|
||||
<span class="GPIO_IO12 GPIO_item" id="GPIO_LEDNumbers_text">Numbers of LEDs</span>
|
||||
</td>
|
||||
<td>
|
||||
<input type="number" name="name" id="GPIO_LEDNumbers_value1" size="13" min="1">
|
||||
</td>
|
||||
<td style="font-size: 80%;">
|
||||
Number of LEDs on the external LED-stripe
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="GPIO_IO12 GPIO_item" id="LEDRGBex9">
|
||||
<td width="20px" style="padding-left: 40px;">
|
||||
</td>
|
||||
<td>
|
||||
<span class="GPIO_IO12 GPIO_item" id="GPIO_LEDColor_text">LED Color</span>
|
||||
</td>
|
||||
<td class="GPIO_IO12 GPIO_item">
|
||||
R <input class="smallSelect" class="GPIO_IO12 GPIO_item" id="GPIO_LEDColor_value1" size="12">
|
||||
G <input class="smallSelect" class="GPIO_IO12 GPIO_item" id="GPIO_LEDColor_value2" size="12">
|
||||
B <input class="smallSelect" class="GPIO_IO12 GPIO_item" id="GPIO_LEDColor_value3" size="12">
|
||||
</td>
|
||||
<td style="font-size: 80%;">
|
||||
Color of LEDs in (R)ed, (G)reen (B)lue from 0...255
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
<!------------- GPIO12 end ------------------>
|
||||
|
||||
<!------------- GPIO13 begin ------------------>
|
||||
<tr class="GPIO_IO13 GPIO_item">
|
||||
<tr class="expert" class="GPIO_IO13 GPIO_item">
|
||||
<td width="20px" style="padding-left: 40px;">
|
||||
<input type="checkbox" id="GPIO_IO13_enabled" value="1" onclick = 'InvertEnableItem("GPIO", "IO13")' unchecked>
|
||||
</td>
|
||||
@@ -1140,9 +1176,6 @@ textarea {
|
||||
<option value="input-pullup">input pullup</option>
|
||||
<option value="input-pulldown">input pulldown</option>
|
||||
<option value="output">output</option>
|
||||
<option value="output-pwm" disabled>output pwm (not implemented)</option>
|
||||
<option value="external-flash-pwm" disabled>external flash light pwm controlled (not implemented)</option>
|
||||
<option value="external-flash-ws281x" disabled>external flash light ws281x controlled (not implemented)</option>
|
||||
</select>
|
||||
</td>
|
||||
</td>
|
||||
@@ -1150,10 +1183,10 @@ textarea {
|
||||
GPIO 13 is usable without restrictions
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="GPIO_IO13 GPIO_item">
|
||||
<tr class="expert" class="GPIO_IO13 GPIO_item">
|
||||
<td width="20px" style="padding-left: 40px;"></td>
|
||||
<td>
|
||||
<span>GPIO 13 use interrupt</span>
|
||||
<span class="GPIO_IO13 GPIO_item">GPIO 13 use interrupt</span>
|
||||
</td>
|
||||
<td>
|
||||
<td">
|
||||
@@ -1171,10 +1204,10 @@ textarea {
|
||||
GPIO 13 enable interrupt trigger
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="GPIO_IO13 GPIO_item">
|
||||
<tr class="expert" class="GPIO_IO13 GPIO_item">
|
||||
<td width="20px" style="padding-left: 40px;"></td>
|
||||
<td>
|
||||
<span>GPIO 13 PWM duty resolution</span>
|
||||
<span class="GPIO_IO13 GPIO_item">GPIO 13 PWM duty resolution</span>
|
||||
</td>
|
||||
<td>
|
||||
<td"><input type="number" id="GPIO_IO13_value3" min="1" max="20"></td>
|
||||
@@ -1183,10 +1216,10 @@ textarea {
|
||||
GPIO 13 LEDC PWM duty resolution in bit
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="GPIO_IO13 GPIO_item">
|
||||
<tr class="expert" class="GPIO_IO13 GPIO_item">
|
||||
<td width="20px" style="padding-left: 40px;"></td>
|
||||
<td>
|
||||
<span>GPIO 13 enable MQTT</span>
|
||||
<span class="GPIO_IO13 GPIO_item">GPIO 13 enable MQTT</span>
|
||||
</td>
|
||||
<td>
|
||||
<td"><input type="checkbox" id="GPIO_IO13_value4"></td>
|
||||
@@ -1195,10 +1228,10 @@ textarea {
|
||||
GPIO 13 enable MQTT publishing/subscribing
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="GPIO_IO13 GPIO_item">
|
||||
<tr class="expert" class="GPIO_IO13 GPIO_item">
|
||||
<td width="20px" style="padding-left: 40px;"></td>
|
||||
<td>
|
||||
<span>GPIO 13 enable HTTP</span>
|
||||
<span class="GPIO_IO13 GPIO_item">GPIO 13 enable HTTP</span>
|
||||
</td>
|
||||
<td>
|
||||
<td"><input type="checkbox" id="GPIO_IO13_value5"></td>
|
||||
@@ -1207,10 +1240,10 @@ textarea {
|
||||
GPIO 13 enable HTTP write/read
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="GPIO_IO13 GPIO_item">
|
||||
<tr class="expert" class="GPIO_IO13 GPIO_item">
|
||||
<td width="20px" style="padding-left: 40px;"></td>
|
||||
<td>
|
||||
<span>GPIO 13 name</span>
|
||||
<span class="GPIO_IO13 GPIO_item">GPIO 13 name</span>
|
||||
</td>
|
||||
<td>
|
||||
<td"><input type="text" id="GPIO_IO13_value6"></td>
|
||||
@@ -1496,6 +1529,11 @@ function InvertEnableItem(_cat, _param)
|
||||
}
|
||||
|
||||
function setEnabled(className, enabled) {
|
||||
_color = "color:lightgrey;";
|
||||
if (enabled) {
|
||||
_color = "color:black;";
|
||||
}
|
||||
|
||||
let elements = document.getElementsByClassName(className);
|
||||
for (i = 0; i < elements.length; i++) {
|
||||
if (enabled) {
|
||||
@@ -1509,6 +1547,7 @@ function setEnabled(className, enabled) {
|
||||
if (inputs[j].id.endsWith("_enabled"))
|
||||
continue;
|
||||
|
||||
inputs[j].style = _color
|
||||
if (enabled) {
|
||||
inputs[j].removeAttribute("disabled");
|
||||
} else {
|
||||
@@ -1700,6 +1739,9 @@ function UpdateInput() {
|
||||
WriteParameter(param, category, "GPIO", "IO4", true);
|
||||
WriteParameter(param, category, "GPIO", "IO12", true);
|
||||
WriteParameter(param, category, "GPIO", "IO13", true);
|
||||
WriteParameter(param, category, "GPIO", "LEDType", false);
|
||||
WriteParameter(param, category, "GPIO", "LEDNumbers", false);
|
||||
WriteParameter(param, category, "GPIO", "LEDColor", false);
|
||||
|
||||
WriteParameter(param, category, "AutoTimer", "AutoStart", false);
|
||||
WriteParameter(param, category, "AutoTimer", "Intervall", false);
|
||||
@@ -1763,6 +1805,16 @@ function ReadParameterAll()
|
||||
ReadParameter(param, "GPIO", "IO4", true);
|
||||
ReadParameter(param, "GPIO", "IO12", true);
|
||||
ReadParameter(param, "GPIO", "IO13", true);
|
||||
ReadParameter(param, "GPIO", "LEDType", false);
|
||||
ReadParameter(param, "GPIO", "LEDNumbers", false);
|
||||
ReadParameter(param, "GPIO", "LEDColor", false);
|
||||
// Folgende Zeilen sind für Abwärtskompatibität < v9.0.0 notwendig (manchmal parameter auskommentiert)
|
||||
param["GPIO"]["LEDType"]["enabled"] = true;
|
||||
param["GPIO"]["LEDNumbers"]["enabled"] = true;
|
||||
param["GPIO"]["LEDColor"]["enabled"] = true;
|
||||
param["GPIO"]["LEDType"]["found"] = true;
|
||||
param["GPIO"]["LEDNumbers"]["found"] = true;
|
||||
param["GPIO"]["LEDColor"]["found"] = true;
|
||||
|
||||
ReadParameter(param, "AutoTimer", "AutoStart", false);
|
||||
ReadParameter(param, "AutoTimer", "Intervall", false);
|
||||
@@ -1799,9 +1851,13 @@ function UpdateAfterCategoryCheck() {
|
||||
|
||||
function UpdateExpertModus()
|
||||
{
|
||||
var _style = 'display:none;';
|
||||
// var _style = 'display:none;';
|
||||
var _style_pur = 'none';
|
||||
var _hidden = true;
|
||||
if (document.getElementById("ExpertModus_enabled").checked) {
|
||||
_style = '';
|
||||
// _style = '';
|
||||
_style_pur = '';
|
||||
_hidden = false;
|
||||
document.getElementById("Edit_Config_Direct").style.display = "";
|
||||
}
|
||||
else
|
||||
@@ -1811,8 +1867,22 @@ function UpdateExpertModus()
|
||||
|
||||
const expert = document.querySelectorAll(".expert");
|
||||
for (var i = 0; i < expert.length; i++) {
|
||||
document.getElementById(expert[i].id).style = _style;
|
||||
expert[i].style.display = _style_pur;
|
||||
// document.getElementById(expert[i].id).style = _style;
|
||||
}
|
||||
|
||||
|
||||
// Enable / Disable die Optionen in den Menues für die Auswahl. Falls kein Expertenmodus soll nur ein Wert (built-in-led oder externan-flash-ws281x) möglich sein
|
||||
Array.from(document.querySelector("#GPIO_IO4_value1").options).forEach(function(option_element) {
|
||||
if (option_element.value != "built-in-led")
|
||||
option_element.hidden = _hidden;
|
||||
});
|
||||
|
||||
Array.from(document.querySelector("#GPIO_IO12_value1").options).forEach(function(option_element) {
|
||||
if (option_element.value != "external-flash-ws281x")
|
||||
option_element.hidden = _hidden;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function saveTextAsFile()
|
||||
|
||||
@@ -3,13 +3,16 @@ function gethost_Version(){
|
||||
return "1.0.0 - 20200910";
|
||||
}
|
||||
|
||||
|
||||
function getbasepath(){
|
||||
var host = window.location.hostname;
|
||||
if ((host == "127.0.0.1") || (host == "localhost") || (host == ""))
|
||||
if (((host == "127.0.0.1") || (host == "localhost") || (host == ""))
|
||||
&& ((window.location.port == "80") || (window.location.port == "")))
|
||||
|
||||
{
|
||||
// host = "http://192.168.2.219"; // jomjol interner test
|
||||
// host = "http://192.168.178.46"; // jomjol interner test
|
||||
host = "http://192.168.178.22"; // jomjol interner Real
|
||||
host = "http://192.168.178.79"; // jomjol interner Real
|
||||
// host = "http://192.168.43.191";
|
||||
// host = "."; // jomjol interner localhost
|
||||
|
||||
@@ -18,6 +21,10 @@ function getbasepath(){
|
||||
{
|
||||
host = "http://" + host;
|
||||
}
|
||||
|
||||
if (window.location.port != "") {
|
||||
host = host + ":" + window.location.port;
|
||||
}
|
||||
return host;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@ function readconfig_Version(){
|
||||
return "1.0.0 - 20200910";
|
||||
}
|
||||
|
||||
var config_gesamt;
|
||||
var config_split;
|
||||
var param;
|
||||
var config_gesamt = "";
|
||||
var config_split = [];
|
||||
var param = [];
|
||||
var category;
|
||||
var ref = new Array(2);
|
||||
var NUMBERS = new Array(0);
|
||||
@@ -104,6 +104,12 @@ function ParseConfig() {
|
||||
ParamAddValue(param, catname, "LEDType");
|
||||
ParamAddValue(param, catname, "LEDNumbers");
|
||||
ParamAddValue(param, catname, "LEDColor", 3);
|
||||
// Default Values, um abwärtskompatiblität zu gewährleisten
|
||||
param[catname]["LEDType"]["value1"] = "WS2812";
|
||||
param[catname]["LEDNumbers"]["value1"] = "2";
|
||||
param[catname]["LEDColor"]["value1"] = "50";
|
||||
param[catname]["LEDColor"]["value2"] = "50";
|
||||
param[catname]["LEDColor"]["value3"] = "50";
|
||||
|
||||
|
||||
var catname = "AutoTimer";
|
||||
|
||||
@@ -1 +1 @@
|
||||
10.2.0
|
||||
11.1.0
|
||||