Merge branch 'master' into multi-button

This commit is contained in:
Christian Schwinne 2021-05-28 10:03:27 +02:00 committed by GitHub
commit 669a610e36
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
31 changed files with 868 additions and 27 deletions

View File

@ -2,6 +2,11 @@
### Builds after release 0.12.0
#### Build 2105230
- No longer retain MQTT `/v` topic to alleviate storage loads on MQTT broker
- Fixed Sunrise calculation (atan_t approx. used outside of value range)
#### Build 2105200
- Fixed WS281x output on ESP32

View File

@ -473,3 +473,37 @@ platform_packages = ${common.platform_packages}
board_build.ldscript = ${common.ldscript_4m1m}
build_unflags = ${common.build_unflags}
build_flags = ${common.build_flags_esp8266}
# ------------------------------------------------------------------------------
# EleksTube-IPS
# ------------------------------------------------------------------------------
[env:elekstube_ips]
board = esp32dev
platform = espressif32@3.2
upload_speed = 921600
lib_deps = ${env.lib_deps}
TFT_eSPI
build_flags = ${common.build_flags_esp32} -D WLED_DISABLE_BROWNOUT_DET -D WLED_DISABLE_INFRARED
-D USERMOD_RTC
-D USERMOD_ELEKSTUBE_IPS
-D LEDPIN=12
-D RLYPIN=27
-D BTNPIN=34
-D WLED_DISABLE_INFRARED
-D DEFAULT_LED_COUNT=6
# Display config
-D ST7789_DRIVER
-D TFT_WIDTH=135
-D TFT_HEIGHT=240
-D CGRAM_OFFSET
-D TFT_SDA_READ
-D TFT_MOSI=23
-D TFT_SCLK=18
-D TFT_DC=25
-D TFT_RST=26
-D SPI_FREQUENCY=40000000
-D USER_SETUP_LOADED
monitor_filters = esp32_exception_decoder
lib_ignore =
ESPAsyncTCP
ESPAsyncUDP

View File

@ -0,0 +1,70 @@
#ifndef CHIP_SELECT_H
#define CHIP_SELECT_H
#include "Hardware.h"
/*
* `digit`s are as defined in Hardware.h, 0 == seconds ones, 5 == hours tens.
*/
class ChipSelect {
private:
uint8_t digits_map;
const uint8_t all_on = 0x3F;
const uint8_t all_off = 0x00;
public:
ChipSelect() : digits_map(all_off) {}
void update() {
// Documented in README.md. Q7 and Q6 are unused. Q5 is Seconds Ones, Q0 is Hours Tens.
// Q7 is the first bit written, Q0 is the last. So we push two dummy bits, then start with
// Seconds Ones and end with Hours Tens.
// CS is Active Low, but digits_map is 1 for enable, 0 for disable. So we bit-wise NOT first.
uint8_t to_shift = (~digits_map) << 2;
digitalWrite(CSSR_LATCH_PIN, LOW);
shiftOut(CSSR_DATA_PIN, CSSR_CLOCK_PIN, LSBFIRST, to_shift);
digitalWrite(CSSR_LATCH_PIN, HIGH);
}
void begin()
{
pinMode(CSSR_LATCH_PIN, OUTPUT);
pinMode(CSSR_DATA_PIN, OUTPUT);
pinMode(CSSR_CLOCK_PIN, OUTPUT);
digitalWrite(CSSR_DATA_PIN, LOW);
digitalWrite(CSSR_CLOCK_PIN, LOW);
digitalWrite(CSSR_LATCH_PIN, LOW);
update();
}
// These speak the indexes defined in Hardware.h.
// So 0 is disabled, 1 is enabled (even though CS is active low, this gets mapped.)
// So bit 0 (LSB), is index 0, is SECONDS_ONES
// Translation to what the 74HC595 uses is done in update()
void setDigitMap(uint8_t map, bool update_=true) { digits_map = map; if (update_) update(); }
uint8_t getDigitMap() { return digits_map; }
// Helper functions
// Sets just the one digit by digit number
void setDigit(uint8_t digit, bool update_=true) { setDigitMap(0x01 << digit, update_); }
void setAll(bool update_=true) { setDigitMap(all_on, update_); }
void clear(bool update_=true) { setDigitMap(all_off, update_); }
void setSecondsOnes() { setDigit(SECONDS_ONES); }
void setSecondsTens() { setDigit(SECONDS_TENS); }
void setMinutesOnes() { setDigit(MINUTES_ONES); }
void setMinutesTens() { setDigit(MINUTES_TENS); }
void setHoursOnes() { setDigit(HOURS_ONES); }
void setHoursTens() { setDigit(HOURS_TENS); }
bool isSecondsOnes() { return (digits_map&SECONDS_ONES_MAP > 0); }
bool isSecondsTens() { return (digits_map&SECONDS_TENS_MAP > 0); }
bool isMinutesOnes() { return (digits_map&MINUTES_ONES_MAP > 0); }
bool isMinutesTens() { return (digits_map&MINUTES_TENS_MAP > 0); }
bool isHoursOnes() { return (digits_map&HOURS_ONES_MAP > 0); }
bool isHoursTens() { return (digits_map&HOURS_TENS_MAP > 0); }
};
#endif // CHIP_SELECT_H

View File

@ -0,0 +1,52 @@
/*
* Define the hardware for the EleksTube IPS clock. Mostly pin definitions
*/
#ifndef ELEKSTUBEHAX_HARDWARE_H
#define ELEKSTUBEHAX_HARDWARE_H
#include <stdint.h>
#include <Arduino.h> // for HIGH and LOW
// Common indexing scheme, used to identify the digit
#define SECONDS_ONES (0)
#define SECONDS_TENS (1)
#define MINUTES_ONES (2)
#define MINUTES_TENS (3)
#define HOURS_ONES (4)
#define HOURS_TENS (5)
#define NUM_DIGITS (6)
#define SECONDS_ONES_MAP (0x01 << SECONDS_ONES)
#define SECONDS_TENS_MAP (0x01 << SECONDS_TENS)
#define MINUTES_ONES_MAP (0x01 << MINUTES_ONES)
#define MINUTES_TENS_MAP (0x01 << MINUTES_TENS)
#define HOURS_ONES_MAP (0x01 << HOURS_ONES)
#define HOURS_TENS_MAP (0x01 << HOURS_TENS)
// WS2812 (or compatible) LEDs on the back of the display modules.
#define BACKLIGHTS_PIN (12)
// Buttons, active low, externally pulled up (with actual resistors!)
#define BUTTON_LEFT_PIN (33)
#define BUTTON_MODE_PIN (32)
#define BUTTON_RIGHT_PIN (35)
#define BUTTON_POWER_PIN (34)
// I2C to DS3231 RTC.
#define RTC_SCL_PIN (22)
#define RTC_SDA_PIN (21)
// Chip Select shift register, to select the display
#define CSSR_DATA_PIN (14)
#define CSSR_CLOCK_PIN (16)
#define CSSR_LATCH_PIN (17)
// SPI to displays
// DEFINED IN User_Setup.h
// Look for: TFT_MOSI, TFT_SCLK, TFT_CS, TFT_DC, and TFT_RST
// Power for all TFT displays are grounded through a MOSFET so they can all be turned off.
// Active HIGH.
#define TFT_ENABLE_PIN (27)
#endif // ELEKSTUBEHAX_HARDWARE_H

View File

@ -0,0 +1,169 @@
#ifndef TFTS_H
#define TFTS_H
#include <FS.h>
#include <TFT_eSPI.h>
#include "Hardware.h"
#include "ChipSelect.h"
class TFTs : public TFT_eSPI {
private:
uint8_t digits[NUM_DIGITS];
// These read 16- and 32-bit types from the SD card file.
// BMP data is stored little-endian, Arduino is little-endian too.
// May need to reverse subscript order if porting elsewhere.
uint16_t read16(fs::File &f) {
uint16_t result;
((uint8_t *)&result)[0] = f.read(); // LSB
((uint8_t *)&result)[1] = f.read(); // MSB
return result;
}
uint32_t read32(fs::File &f) {
uint32_t result;
((uint8_t *)&result)[0] = f.read(); // LSB
((uint8_t *)&result)[1] = f.read();
((uint8_t *)&result)[2] = f.read();
((uint8_t *)&result)[3] = f.read(); // MSB
return result;
}
uint16_t output_buffer[TFT_HEIGHT][TFT_WIDTH];
// These BMP functions are stolen directly from the TFT_SPIFFS_BMP example in the TFT_eSPI library.
// Unfortunately, they aren't part of the library itself, so I had to copy them.
// I've modified drawBmp to buffer the whole image at once instead of doing it line-by-line.
//// BEGIN STOLEN CODE
bool drawBmp(const char *filename) {
fs::File bmpFS;
// Open requested file on SD card
bmpFS = WLED_FS.open(filename, "r");
if (!bmpFS)
{
Serial.println(F("File not found"));
return(false);
}
uint32_t seekOffset;
int16_t w, h, row;
uint8_t r, g, b;
uint16_t magic = read16(bmpFS);
if (magic == 0xFFFF) {
Serial.println(F("BMP not found!"));
bmpFS.close();
return(false);
}
if (magic != 0x4D42) {
Serial.print(F("File not a BMP. Magic: "));
Serial.println(magic);
bmpFS.close();
return(false);
}
read32(bmpFS);
read32(bmpFS);
seekOffset = read32(bmpFS);
read32(bmpFS);
w = read32(bmpFS);
h = read32(bmpFS);
if ((read16(bmpFS) != 1) || (read16(bmpFS) != 24) || (read32(bmpFS) != 0)) {
Serial.println(F("BMP format not recognized."));
bmpFS.close();
return(false);
}
//draw img that is shorter than 240pix into the center
int16_t y = (height() - h) /2;
bool oldSwapBytes = getSwapBytes();
setSwapBytes(true);
bmpFS.seek(seekOffset);
uint16_t padding = (4 - ((w * 3) & 3)) & 3;
uint8_t lineBuffer[w * 3 + padding];
// row is decremented as the BMP image is drawn bottom up
for (row = h-1; row >= 0; row--) {
if (row & 0b00000111 == 7) strip.service(); //still refresh backlight to mitigate stutter every few rows
bmpFS.read(lineBuffer, sizeof(lineBuffer));
uint8_t* bptr = lineBuffer;
// Convert 24 to 16 bit colours while copying to output buffer.
for (uint16_t col = 0; col < w; col++)
{
b = *bptr++;
g = *bptr++;
r = *bptr++;
output_buffer[row][col] = ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
}
}
pushImage(0, y, w, h, (uint16_t *)output_buffer);
setSwapBytes(oldSwapBytes);
bmpFS.close();
return(true);
}
public:
TFTs() : TFT_eSPI(), chip_select()
{ for (uint8_t digit=0; digit < NUM_DIGITS; digit++) digits[digit] = 0; }
// no == Do not send to TFT. yes == Send to TFT if changed. force == Send to TFT.
enum show_t { no, yes, force };
// A digit of 0xFF means blank the screen.
const static uint8_t blanked = 255;
void begin() {
pinMode(TFT_ENABLE_PIN, OUTPUT);
digitalWrite(TFT_ENABLE_PIN, HIGH); //enable displays on boot
// Start with all displays selected.
chip_select.begin();
chip_select.setAll();
// Initialize the super class.
init();
}
void showDigit(uint8_t digit) {
chip_select.setDigit(digit);
if (digits[digit] == blanked) {
fillScreen(TFT_BLACK);
}
else {
// Filenames are no bigger than "255.bmp\0"
char file_name[10];
sprintf(file_name, "/%d.bmp", digits[digit]);
drawBmp(file_name);
}
}
void setDigit(uint8_t digit, uint8_t value, show_t show=yes) {
uint8_t old_value = digits[digit];
digits[digit] = value;
if (show != no && (old_value != value || show == force)) {
showDigit(digit);
}
}
uint8_t getDigit(uint8_t digit) { return digits[digit]; }
void showAllDigits() { for (uint8_t digit=0; digit < NUM_DIGITS; digit++) showDigit(digit); }
// Making chip_select public so we don't have to proxy all methods, and the caller can just use it directly.
ChipSelect chip_select;
};
#endif // TFTS_H

View File

@ -0,0 +1,47 @@
/*
* This is intended to over-ride `User_Setup.h` that comes with the TFT_eSPI library.
* I hate having to modify the library code.
*/
// ST7789 135 x 240 display with no chip select line
#define ST7789_DRIVER // Configure all registers
#define TFT_WIDTH 135
#define TFT_HEIGHT 240
#define CGRAM_OFFSET // Library will add offsets required
//#define TFT_RGB_ORDER TFT_RGB // Colour order Red-Green-Blue
//#define TFT_RGB_ORDER TFT_BGR // Colour order Blue-Green-Red
//#define TFT_INVERSION_ON
//#define TFT_INVERSION_OFF
// EleksTube IPS
#define TFT_SDA_READ // Read and write on the MOSI/SDA pin, no separate MISO pin
#define TFT_MOSI 23
#define TFT_SCLK 18
//#define TFT_CS -1 // Not connected
#define TFT_DC 25 // Data Command, aka Register Select or RS
#define TFT_RST 26 // Connect reset to ensure display initialises
#define LOAD_GLCD // Font 1. Original Adafruit 8 pixel font needs ~1820 bytes in FLASH
//#define LOAD_FONT2 // Font 2. Small 16 pixel high font, needs ~3534 bytes in FLASH, 96 characters
//#define LOAD_FONT4 // Font 4. Medium 26 pixel high font, needs ~5848 bytes in FLASH, 96 characters
//#define LOAD_FONT6 // Font 6. Large 48 pixel font, needs ~2666 bytes in FLASH, only characters 1234567890:-.apm
//#define LOAD_FONT7 // Font 7. 7 segment 48 pixel font, needs ~2438 bytes in FLASH, only characters 1234567890:.
//#define LOAD_FONT8 // Font 8. Large 75 pixel font needs ~3256 bytes in FLASH, only characters 1234567890:-.
//#define LOAD_FONT8N // Font 8. Alternative to Font 8 above, slightly narrower, so 3 digits fit a 160 pixel TFT
//#define LOAD_GFXFF // FreeFonts. Include access to the 48 Adafruit_GFX free fonts FF1 to FF48 and custom fonts
//#define SMOOTH_FONT
//#define SPI_FREQUENCY 27000000
#define SPI_FREQUENCY 40000000
/*
* To make the Library not over-write all this:
*/
#define USER_SETUP_LOADED

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

View File

@ -0,0 +1,21 @@
# EleksTube IPS Clock usermod
This usermod allows WLED to run on the EleksTube IPS clock.
It enables running all WLED effects on the background SK6812 lighting, while displaying digit bitmaps on the 6 IPS screens.
Code is largely based on https://github.com/SmittyHalibut/EleksTubeHAX by Mark Smith!
Supported:
- Display with custom bitmaps from filesystem
- Background lighting
- Power button
- RTC (with RTC usermod)
- Standard WLED time features (NTP, DST, timezones)
Not supported:
- 3 navigation buttons, on-device setup
## Installation
Compile and upload to clock using the `elekstube_ips` PlatformIO environment
Once uploaded (the clock can be flashed like any ESP32 module), go to `[WLED-IP]/edit` and upload the 0-9.bmp files from the bmp folder.
Use LED pin 12, relay pin 27 and button pin 34.

View File

@ -0,0 +1,63 @@
#pragma once
#include "TFTs.h"
#include "wled.h"
//Large parts of the code are from https://github.com/SmittyHalibut/EleksTubeHAX
class ElekstubeIPSUsermod : public Usermod {
private:
TFTs tfts;
void updateClockDisplay(TFTs::show_t show=TFTs::yes) {
bool set[6] = {false};
for (uint8_t i = 0; i<6; i++) {
char c = cronixieDisplay[i];
if (c >= '0' && c <= '9') {
tfts.setDigit(5-i, c - '0', show); set[i] = true;
} else if (c >= 'A' && c <= 'G') {
tfts.setDigit(5-i, c - 'A' + 10, show); set[i] = true; //10.bmp to 16.bmp static display
} else if (c == '-' || c == '_' || c == ' ') {
tfts.setDigit(5-i, 255, show); set[i] = true; //blank
} else {
set[i] = false; //display HHMMSS time
}
}
uint8_t hr = hour(localTime);
uint8_t hrTens = hr/10;
uint8_t mi = minute(localTime);
uint8_t mittens = mi/10;
uint8_t s = second(localTime);
uint8_t sTens = s/10;
if (!set[0]) tfts.setDigit(HOURS_TENS, hrTens, show);
if (!set[1]) tfts.setDigit(HOURS_ONES, hr - hrTens*10, show);
if (!set[2]) tfts.setDigit(MINUTES_TENS, mittens, show);
if (!set[3]) tfts.setDigit(MINUTES_ONES, mi - mittens*10, show);
if (!set[4]) tfts.setDigit(SECONDS_TENS, sTens, show);
if (!set[5]) tfts.setDigit(SECONDS_ONES, s - sTens*10, show);
}
unsigned long lastTime = 0;
public:
void setup() {
tfts.begin();
tfts.fillScreen(TFT_BLACK);
tfts.setTextColor(TFT_WHITE, TFT_BLACK);
tfts.setCursor(0, 0, 2);
tfts.println("<STARTUP>");
}
void loop() {
if (lastTime == 0) {
tfts.fillScreen(TFT_BLACK);
updateClockDisplay(TFTs::force);
}
if (millis() - lastTime > 100) {
updateClockDisplay();
lastTime = millis();
}
}
uint16_t getId()
{
return USERMOD_ID_ELEKSTUBE_IPS;
}
};

8
usermods/RTC/readme.md Normal file
View File

@ -0,0 +1,8 @@
# DS1307/DS3231 Real time clock
Gets the time from I2C RTC module on boot. This allows clocks to operate e.g. if temporarily no WiFi is available.
The stored time is updated each time NTP is synced.
## Installation
Add the build flag `-D USERMOD_RTC` to your platformio environment.

View File

@ -0,0 +1,37 @@
#pragma once
#include "src/dependencies/time/DS1307RTC.h"
#include "wled.h"
//Connect DS1307 to standard I2C pins (ESP32: GPIO 21 (SDA)/GPIO 22 (SCL))
class RTCUsermod : public Usermod {
private:
unsigned long lastTime = 0;
bool disabled = false;
public:
void setup() {
time_t rtcTime = RTC.get();
if (rtcTime) {
setTime(rtcTime);
updateLocalTime();
} else {
if (!RTC.chipPresent()) disabled = true; //don't waste time if H/W error
}
}
void loop() {
if (!disabled && millis() - lastTime > 500) {
time_t t = now();
if (t != RTC.get()) RTC.set(t); //set RTC to NTP/UI-provided value
lastTime = millis();
}
}
uint16_t getId()
{
return USERMOD_ID_RTC;
}
};

View File

@ -9,7 +9,7 @@ build_unflags = ${common.build_unflags}
build_flags =
${common.build_flags_esp32}
-D USERMOD_MODE_SORT
-D USERMOD_FOUR_LINE_DISLAY -D FLD_PIN_SCL=22 -D FLD_PIN_SDA=21
-D USERMOD_FOUR_LINE_DISPLAY -D FLD_PIN_SCL=22 -D FLD_PIN_SDA=21
-D USERMOD_ROTARY_ENCODER_UI -D ENCODER_DT_PIN=18 -D ENCODER_CLK_PIN=5 -D ENCODER_SW_PIN=19
-D USERMOD_AUTO_SAVE -D AUTOSAVE_PRESET_NUM=1
-D LEDPIN=16 -D BTNPIN=13
@ -28,7 +28,7 @@ build_unflags = ${common.build_unflags}
build_flags =
${common.build_flags_esp8266}
-D USERMOD_MODE_SORT
-D USERMOD_FOUR_LINE_DISLAY -D FLD_PIN_SCL=5 -D FLD_PIN_SDA=4
-D USERMOD_FOUR_LINE_DISPLAY -D FLD_PIN_SCL=5 -D FLD_PIN_SDA=4
-D USERMOD_ROTARY_ENCODER_UI -D ENCODER_DT_PIN=12 -D ENCODER_CLK_PIN=14 -D ENCODER_SW_PIN=13
-D USERMOD_AUTO_SAVE -D AUTOSAVE_PRESET_NUM=1
-D LEDPIN=3 -D BTNPIN=0

View File

@ -16,7 +16,7 @@ This file should be placed in the same directory as `platformio.ini`.
### Define Your Options
* `USERMOD_ROTARY_ENCODER_UI` - define this to have this user mod included wled00\usermods_list.cpp
* `USERMOD_FOUR_LINE_DISLAY` - define this to have this the Four Line Display mod included wled00\usermods_list.cpp - also tells this usermod that the display is available (see the Four Line Display usermod `readme.md` for more details)
* `USERMOD_FOUR_LINE_DISPLAY` - define this to have this the Four Line Display mod included wled00\usermods_list.cpp - also tells this usermod that the display is available (see the Four Line Display usermod `readme.md` for more details)
* `ENCODER_DT_PIN` - The encoders DT pin, defaults to 12
* `ENCODER_CLK_PIN` - The encoders CLK pin, defaults to 14
* `ENCODER_SW_PIN` - The encoders SW pin, defaults to 13

View File

@ -37,7 +37,7 @@
#define ENCODER_SW_PIN 13
#endif
#ifndef USERMOD_FOUR_LINE_DISLAY
#ifndef USERMOD_FOUR_LINE_DISPLAY
// These constants won't be defined if we aren't using FourLineDisplay.
#define FLD_LINE_3_BRIGHTNESS 0
#define FLD_LINE_3_EFFECT_SPEED 0
@ -62,7 +62,7 @@ private:
unsigned char button_state = HIGH;
unsigned char prev_button_state = HIGH;
#ifdef USERMOD_FOUR_LINE_DISLAY
#ifdef USERMOD_FOUR_LINE_DISPLAY
FourLineDisplayUsermod *display;
#else
void* display = nullptr;
@ -96,7 +96,7 @@ public:
modes_alpha_indexes = modeSortUsermod->getModesAlphaIndexes();
palettes_alpha_indexes = modeSortUsermod->getPalettesAlphaIndexes();
#ifdef USERMOD_FOUR_LINE_DISLAY
#ifdef USERMOD_FOUR_LINE_DISPLAY
// This Usermod uses FourLineDisplayUsermod for the best experience.
// But it's optional. But you want it.
display = (FourLineDisplayUsermod*) usermods.lookup(USERMOD_ID_FOUR_LINE_DISP);
@ -248,7 +248,7 @@ public:
}
boolean changeState(const char *stateName, byte lineThreeMode, byte markedLine) {
#ifdef USERMOD_FOUR_LINE_DISLAY
#ifdef USERMOD_FOUR_LINE_DISPLAY
if (display != nullptr) {
if (display->wakeDisplay()) {
// Throw away wake up input
@ -272,7 +272,7 @@ public:
}
void changeBrightness(bool increase) {
#ifdef USERMOD_FOUR_LINE_DISLAY
#ifdef USERMOD_FOUR_LINE_DISPLAY
if (display && display->wakeDisplay()) {
// Throw away wake up input
return;
@ -288,7 +288,7 @@ public:
}
void changeEffect(bool increase) {
#ifdef USERMOD_FOUR_LINE_DISLAY
#ifdef USERMOD_FOUR_LINE_DISPLAY
if (display && display->wakeDisplay()) {
// Throw away wake up input
return;
@ -305,7 +305,7 @@ public:
}
void changeEffectSpeed(bool increase) {
#ifdef USERMOD_FOUR_LINE_DISLAY
#ifdef USERMOD_FOUR_LINE_DISPLAY
if (display && display->wakeDisplay()) {
// Throw away wake up input
return;
@ -321,7 +321,7 @@ public:
}
void changeEffectIntensity(bool increase) {
#ifdef USERMOD_FOUR_LINE_DISLAY
#ifdef USERMOD_FOUR_LINE_DISPLAY
if (display && display->wakeDisplay()) {
// Throw away wake up input
return;
@ -337,7 +337,7 @@ public:
}
void changePalette(bool increase) {
#ifdef USERMOD_FOUR_LINE_DISLAY
#ifdef USERMOD_FOUR_LINE_DISPLAY
if (display && display->wakeDisplay()) {
// Throw away wake up input
return;

View File

@ -49,7 +49,7 @@
//#define DEFAULT_LED_TYPE TYPE_WS2812_RGB
#ifndef PIXEL_COUNTS
#define PIXEL_COUNTS 30
#define PIXEL_COUNTS DEFAULT_LED_COUNT
#endif
#ifndef DATA_PINS

View File

@ -55,6 +55,8 @@
#define USERMOD_ID_VL53L0X 12 //Usermod "usermod_vl53l0x_gestures.h"
#define USERMOD_ID_MULTI_RELAY 13 //Usermod "usermod_multi_relay.h"
#define USERMOD_ID_ANIMATED_STAIRCASE 14 //Usermod "Animated_Staircase.h"
#define USERMOD_ID_RTC 15 //Usermod "usermod_rtc.h"
#define USERMOD_ID_ELEKSTUBE_IPS 16 //Usermod "usermod_elekstube_ips.h"
//Access point behavior
#define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot

View File

@ -270,6 +270,10 @@ bool deserializeState(JsonObject root)
}
}
if (root["nx"].is<const char*>()) {
strncpy(cronixieDisplay, root["nx"], 6);
}
usermods.readFromJsonState(root);
int ps = root[F("psave")] | -1;

View File

@ -137,7 +137,7 @@ void publishMqtt()
XML_response(nullptr, apires);
strcpy(subuf, mqttDeviceTopic);
strcat_P(subuf, PSTR("/v"));
mqtt->publish(subuf, 0, true, apires);
mqtt->publish(subuf, 0, false, apires);
}

View File

@ -0,0 +1,218 @@
/*
* DS1307RTC.h - library for DS1307 RTC
Copyright (c) Michael Margolis 2009
This library is intended to be uses with Arduino Time library functions
The library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
30 Dec 2009 - Initial release
5 Sep 2011 updated for Arduino 1.0
*/
#if defined (__AVR_ATtiny84__) || defined(__AVR_ATtiny85__) || (__AVR_ATtiny2313__)
#include <TinyWireM.h>
#define Wire TinyWireM
#else
#include <Wire.h>
#endif
#include "DS1307RTC.h"
#define DS1307_CTRL_ID 0x68
DS1307RTC::DS1307RTC()
{
Wire.begin();
}
// PUBLIC FUNCTIONS
time_t DS1307RTC::get() // Aquire data from buffer and convert to time_t
{
tmElements_t tm;
if (read(tm) == false) return 0;
return(makeTime(tm));
}
bool DS1307RTC::set(time_t t)
{
tmElements_t tm;
breakTime(t, tm);
return write(tm);
}
// Aquire data from the RTC chip in BCD format
bool DS1307RTC::read(tmElements_t &tm)
{
uint8_t sec;
Wire.beginTransmission(DS1307_CTRL_ID);
#if ARDUINO >= 100
Wire.write((uint8_t)0x00);
#else
Wire.send(0x00);
#endif
if (Wire.endTransmission() != 0) {
exists = false;
return false;
}
exists = true;
// request the 7 data fields (secs, min, hr, dow, date, mth, yr)
Wire.requestFrom(DS1307_CTRL_ID, tmNbrFields);
if (Wire.available() < tmNbrFields) return false;
#if ARDUINO >= 100
sec = Wire.read();
tm.Second = bcd2dec(sec & 0x7f);
tm.Minute = bcd2dec(Wire.read() );
tm.Hour = bcd2dec(Wire.read() & 0x3f); // mask assumes 24hr clock
tm.Wday = bcd2dec(Wire.read() );
tm.Day = bcd2dec(Wire.read() );
tm.Month = bcd2dec(Wire.read() );
tm.Year = y2kYearToTm((bcd2dec(Wire.read())));
#else
sec = Wire.receive();
tm.Second = bcd2dec(sec & 0x7f);
tm.Minute = bcd2dec(Wire.receive() );
tm.Hour = bcd2dec(Wire.receive() & 0x3f); // mask assumes 24hr clock
tm.Wday = bcd2dec(Wire.receive() );
tm.Day = bcd2dec(Wire.receive() );
tm.Month = bcd2dec(Wire.receive() );
tm.Year = y2kYearToTm((bcd2dec(Wire.receive())));
#endif
if (sec & 0x80) return false; // clock is halted
return true;
}
bool DS1307RTC::write(tmElements_t &tm)
{
// To eliminate any potential race conditions,
// stop the clock before writing the values,
// then restart it after.
Wire.beginTransmission(DS1307_CTRL_ID);
#if ARDUINO >= 100
Wire.write((uint8_t)0x00); // reset register pointer
Wire.write((uint8_t)0x80); // Stop the clock. The seconds will be written last
Wire.write(dec2bcd(tm.Minute));
Wire.write(dec2bcd(tm.Hour)); // sets 24 hour format
Wire.write(dec2bcd(tm.Wday));
Wire.write(dec2bcd(tm.Day));
Wire.write(dec2bcd(tm.Month));
Wire.write(dec2bcd(tmYearToY2k(tm.Year)));
#else
Wire.send(0x00); // reset register pointer
Wire.send(0x80); // Stop the clock. The seconds will be written last
Wire.send(dec2bcd(tm.Minute));
Wire.send(dec2bcd(tm.Hour)); // sets 24 hour format
Wire.send(dec2bcd(tm.Wday));
Wire.send(dec2bcd(tm.Day));
Wire.send(dec2bcd(tm.Month));
Wire.send(dec2bcd(tmYearToY2k(tm.Year)));
#endif
if (Wire.endTransmission() != 0) {
exists = false;
return false;
}
exists = true;
// Now go back and set the seconds, starting the clock back up as a side effect
Wire.beginTransmission(DS1307_CTRL_ID);
#if ARDUINO >= 100
Wire.write((uint8_t)0x00); // reset register pointer
Wire.write(dec2bcd(tm.Second)); // write the seconds, with the stop bit clear to restart
#else
Wire.send(0x00); // reset register pointer
Wire.send(dec2bcd(tm.Second)); // write the seconds, with the stop bit clear to restart
#endif
if (Wire.endTransmission() != 0) {
exists = false;
return false;
}
exists = true;
return true;
}
unsigned char DS1307RTC::isRunning()
{
Wire.beginTransmission(DS1307_CTRL_ID);
#if ARDUINO >= 100
Wire.write((uint8_t)0x00);
#else
Wire.send(0x00);
#endif
Wire.endTransmission();
// Just fetch the seconds register and check the top bit
Wire.requestFrom(DS1307_CTRL_ID, 1);
#if ARDUINO >= 100
return !(Wire.read() & 0x80);
#else
return !(Wire.receive() & 0x80);
#endif
}
void DS1307RTC::setCalibration(char calValue)
{
unsigned char calReg = abs(calValue) & 0x1f;
if (calValue >= 0) calReg |= 0x20; // S bit is positive to speed up the clock
Wire.beginTransmission(DS1307_CTRL_ID);
#if ARDUINO >= 100
Wire.write((uint8_t)0x07); // Point to calibration register
Wire.write(calReg);
#else
Wire.send(0x07); // Point to calibration register
Wire.send(calReg);
#endif
Wire.endTransmission();
}
char DS1307RTC::getCalibration()
{
Wire.beginTransmission(DS1307_CTRL_ID);
#if ARDUINO >= 100
Wire.write((uint8_t)0x07);
#else
Wire.send(0x07);
#endif
Wire.endTransmission();
Wire.requestFrom(DS1307_CTRL_ID, 1);
#if ARDUINO >= 100
unsigned char calReg = Wire.read();
#else
unsigned char calReg = Wire.receive();
#endif
char out = calReg & 0x1f;
if (!(calReg & 0x20)) out = -out; // S bit clear means a negative value
return out;
}
// PRIVATE FUNCTIONS
// Convert Decimal to Binary Coded Decimal (BCD)
uint8_t DS1307RTC::dec2bcd(uint8_t num)
{
return ((num/10 * 16) + (num % 10));
}
// Convert Binary Coded Decimal (BCD) to Decimal
uint8_t DS1307RTC::bcd2dec(uint8_t num)
{
return ((num/16 * 10) + (num % 16));
}
bool DS1307RTC::exists = false;
DS1307RTC RTC = DS1307RTC(); // create an instance for the user

View File

@ -0,0 +1,40 @@
/*
* DS1307RTC.h - library for DS1307 RTC
* This library is intended to be uses with Arduino Time library functions
*/
#ifndef DS1307RTC_h
#define DS1307RTC_h
#include "TimeLib.h"
// library interface description
class DS1307RTC
{
// user-accessible "public" interface
public:
DS1307RTC();
static time_t get();
static bool set(time_t t);
static bool read(tmElements_t &tm);
static bool write(tmElements_t &tm);
static bool chipPresent() { return exists; }
static unsigned char isRunning();
static void setCalibration(char calValue);
static char getCalibration();
private:
static bool exists;
static uint8_t dec2bcd(uint8_t num);
static uint8_t bcd2dec(uint8_t num);
};
#ifdef RTC
#undef RTC // workaround for Arduino Due, which defines "RTC"...
#endif
extern DS1307RTC RTC;
#endif

View File

@ -61,6 +61,14 @@
#include "../usermods/multi_relay/usermod_multi_relay.h"
#endif
#ifdef USERMOD_RTC
#include "../usermods/RTC/usermod_rtc.h"
#endif
#ifdef USERMOD_ELEKSTUBE_IPS
#include "../usermods/EleksTube_IPS/usermod_elekstube_ips.h"
#endif
void registerUsermods()
{
/*
@ -118,4 +126,12 @@ void registerUsermods()
#ifdef USERMOD_MULTI_RELAY
usermods.add(new MultiRelay());
#endif
#ifdef USERMOD_RTC
usermods.add(new RTCUsermod());
#endif
#ifdef USERMOD_ELEKSTUBE_IPS
usermods.add(new ElekstubeIPSUsermod());
#endif
}

View File

@ -11,6 +11,8 @@
#include <Arduino.h> //PI constant
//#define WLED_DEBUG_MATH
#define modd(x, y) ((x) - (int)((x) / (y)) * (y))
float cos_t(float x)
@ -24,38 +26,58 @@ float cos_t(float x)
}
float xx = x * x;
return sign * (1 - ((xx) / (2)) + ((xx * xx) / (24)) - ((xx * xx * xx) / (720)) + ((xx * xx * xx * xx) / (40320)) - ((xx * xx * xx * xx * xx) / (3628800)) + ((xx * xx * xx * xx * xx * xx) / (479001600)));
float res = sign * (1 - ((xx) / (2)) + ((xx * xx) / (24)) - ((xx * xx * xx) / (720)) + ((xx * xx * xx * xx) / (40320)) - ((xx * xx * xx * xx * xx) / (3628800)) + ((xx * xx * xx * xx * xx * xx) / (479001600)));
#ifdef WLED_DEBUG_MATH
Serial.printf("cos: %f,%f\n",res,cos(x));
#endif
return res;
}
float sin_t(float x) {
return cos_t(HALF_PI - x);
float res = cos_t(HALF_PI - x);
#ifdef WLED_DEBUG_MATH
Serial.printf("sin: %f,%f\n",res,sin(x));
#endif
return res;
}
float tan_t(float x) {
float c = cos_t(x);
if (c==0.0) return 0;
return sin_t(x) / c;
float res = sin_t(x) / c;
#ifdef WLED_DEBUG_MATH
Serial.printf("tan: %f,%f\n",res,tan(x));
#endif
return res;
}
//https://stackoverflow.com/questions/3380628
// Absolute error <= 6.7e-5
float acos_t(float x) {
float negate = float(x < 0);
x = std::abs(x);
float xabs = std::abs(x);
float ret = -0.0187293;
ret = ret * x;
ret = ret * xabs;
ret = ret + 0.0742610;
ret = ret * x;
ret = ret * xabs;
ret = ret - 0.2121144;
ret = ret * x;
ret = ret * xabs;
ret = ret + HALF_PI;
ret = ret * sqrt(1.0-x);
ret = ret * sqrt(1.0-xabs);
ret = ret - 2 * negate * ret;
return negate * PI + ret;
float res = negate * PI + ret;
#ifdef WLED_DEBUG_MATH
Serial.printf("acos,%f,%f,%f\n",x,res,acos(x));
#endif
return res;
}
float asin_t(float x) {
return HALF_PI - acos_t(x);
float res = HALF_PI - acos_t(x);
#ifdef WLED_DEBUG_MATH
Serial.printf("asin,%f,%f,%f\n",x,res,asin(x));
#endif
return res;
}
//https://stackoverflow.com/a/42542593
@ -63,21 +85,54 @@ float asin_t(float x) {
#define B -0.287434475393028
#define C ((HALF_PI/2) - A - B)
//polynominal factors for approximation between 1 and 5
#define C0 0.089494f
#define C1 0.974207f
#define C2 -0.326175f
#define C3 0.05375f
#define C4 -0.003445f
float atan_t(float x) {
float xx = x * x;
return ((A*xx + B)*xx + C)*x;
bool neg = (x < 0);
#ifdef WLED_DEBUG_MATH
float xinput = x;
#endif
x = std::abs(x);
float res;
if (x > 5.0f) { //atan(x) converges to pi/2 - (1/x) for large values
res = HALF_PI - (1.0f/x);
}
else if (x > 1.0f) { //1 < x < 5
float xx = x * x;
res = (C4*xx*xx)+(C3*xx*x)+(C2*xx)+(C1*x)+C0;
} else { //this approximation is only for x <= 1
float xx = x * x;
res = ((A*xx + B)*xx + C)*x;
}
if (neg) res = -res;
#ifdef WLED_DEBUG_MATH
Serial.printf("atan,%f,%f,%f\n",xinput,res,atan(xinput));
#endif
return res;
}
float floor_t(float x) {
bool neg = x < 0;
int val = x;
if (neg) val--;
#ifdef WLED_DEBUG_MATH
Serial.printf("floor: %f,%f\n",val,floor(x));
#endif
return val;
}
float fmod_t(float num, float denom) {
int tquot = num / denom;
return num - tquot * denom;
float res = num - tquot * denom;
#ifdef WLED_DEBUG_MATH
Serial.printf("fmod: %f,%f\n",res,fmod(num,denom));
#endif
return res;
}
#endif