Merge pull request #1332 from Aircoookie/mergefs-201112

Update FS branch
This commit is contained in:
Aircoookie 2020-11-12 11:26:30 +01:00 committed by GitHub
commit aa8c587ac8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 289 additions and 38 deletions

View File

@ -2,6 +2,19 @@
### Development versions after the 0.10.2 release
#### Build 2011120
- Added the ability for the /api MQTT topic to receive JSON API payloads
#### Build 2011040
- Inversed Rain direction (fixes #1147)
#### Build 2011010
- Re-added previous C9 palette
- Renamed new C9 palette
#### Build 2010290
- Colorful effect now supports palettes

View File

@ -11,7 +11,7 @@
# Welcome to my project WLED! ✨
A fast and feature-rich implementation of an ESP8266/ESP32 webserver to control NeoPixel (WS2812B, WS2811, SK6812, APA102) LEDs or also SPI based chipsets like the WS2801!
A fast and feature-rich implementation of an ESP8266/ESP32 webserver to control NeoPixel (WS2812B, WS2811, SK6812) LEDs or also SPI based chipsets like the WS2801 and APA102!
## ⚙️ Features
- WS2812FX library integrated for over 100 special effects
@ -47,15 +47,7 @@ A fast and feature-rich implementation of an ESP8266/ESP32 webserver to control
See the [wiki](https://github.com/Aircoookie/WLED/wiki)!
DrZzs has made some excellent video guides:
[Introduction, hardware and installation](https://www.youtube.com/watch?v=tXvtxwK3jRk)
[Settings, tips and tricks](https://www.youtube.com/watch?v=6eCE2BpLaUQ)
If you'd rather read, here is a very [detailed step-by-step beginner tutorial](https://tynick.com/blog/11-03-2019/getting-started-with-wled-on-esp8266/) by tynick!
Russian speakers, check out the videos by Room31:
[WLED Firmware Overview: Interface and Settings](https://youtu.be/h7lKsczEI7E)
[ESP8266 based LED controller for WS2812b strip. WLED Firmware + OpenHAB](https://youtu.be/K4ioTt3XvGc)
[On this page](https://github.com/Aircoookie/WLED/wiki/Learning-the-ropes) you can find excellent tutorials made by the community and helpful tools to help you get your new lamp up and running!
## 🖼️ Images
<img src="/images/macbook-pro-space-gray-on-the-wooden-table.jpg" width="50%"><img src="/images/walking-with-iphone-x.jpg" width="50%">

View File

@ -0,0 +1,50 @@
# MQTT controllable switches
This usermod allows controlling switches (e.g. relays) via MQTT.
## Usermod installation
1. Copy the file `usermod_mqtt_switch.h` to the `wled00` directory.
2. Register the usermod by adding `#include "usermod_mqtt_switch.h"` in the top and `registerUsermod(new UsermodMqttSwitch());` in the bottom of `usermods_list.cpp`.
Example `usermods_list.cpp`:
```
#include "wled.h"
#include "usermod_mqtt_switch.h"
void registerUsermods()
{
usermods.add(new UsermodMqttSwitch());
}
```
## Define pins
Add a define for MQTTSWITCHPINS to platformio_override.ini.
The following example defines 3 switches connected to the GPIO pins 13, 5 and 2:
```
[env:livingroom]
board = esp12e
platform = ${common.platform_wled_default}
board_build.ldscript = ${common.ldscript_4m1m}
build_flags = ${common.build_flags_esp8266}
-D LEDPIN=3
-D BTNPIN=4
-D RLYPIN=12
-D RLYMDE=1
-D STATUSPIN=15
-D MQTTSWITCHPINS="13, 5, 2"
```
Pins can be inverted by setting `MQTTSWITCHINVERT`. For example `-D MQTTSWITCHINVERT="false, false, true"` would invert the switch on pin 2 in the previous example.
The default state after booting before any MQTT message can be set by `MQTTSWITCHDEFAULTS`. For example `-D MQTTSWITCHDEFAULTS="ON, OFF, OFF"` would power on the switch on pin 13 and power off switches on pins 5 and 2.
## MQTT topics
This usermod listens on `[mqttDeviceTopic]/switch/0/set` (where 0 is replaced with the index of the switch) for commands. Anything starting with `ON` turns on the switch, everything else turns it off.
Feedback about the current state is provided at `[mqttDeviceTopic]/switch/0/state`.
### Home Assistant auto-discovery
Auto-discovery information is automatically published and you shoudn't have to do anything to register the switches in Home Assistant.

View File

@ -0,0 +1,157 @@
#pragma once
#include "wled.h"
#ifndef WLED_ENABLE_MQTT
#error "This user mod requires MQTT to be enabled."
#endif
#ifndef MQTTSWITCHPINS
#error "Please define MQTTSWITCHPINS in platformio_override.ini. e.g. -D MQTTSWITCHPINS="12, 0, 2" "
// The following define helps Eclipse's C++ parser but is never used in production due to the #error statement on the line before
#define MQTTSWITCHPINS 12, 0, 2
#endif
// Default behavior: All outputs active high
#ifndef MQTTSWITCHINVERT
#define MQTTSWITCHINVERT
#endif
// Default behavior: All outputs off
#ifndef MQTTSWITCHDEFAULTS
#define MQTTSWITCHDEFAULTS
#endif
static const uint8_t switchPins[] = { MQTTSWITCHPINS };
//This is a hack to get the number of pins defined by the user
#define NUM_SWITCH_PINS (sizeof(switchPins))
static const bool switchInvert[NUM_SWITCH_PINS] = { MQTTSWITCHINVERT};
//Make settings in config file more readable
#define ON 1
#define OFF 0
static const bool switchDefaults[NUM_SWITCH_PINS] = { MQTTSWITCHDEFAULTS};
#undef ON
#undef OFF
class UsermodMqttSwitch: public Usermod
{
private:
bool mqttInitialized;
bool switchState[NUM_SWITCH_PINS];
public:
UsermodMqttSwitch() :
mqttInitialized(false)
{
}
void setup()
{
for (int pinNr = 0; pinNr < NUM_SWITCH_PINS; pinNr++) {
setState(pinNr, switchDefaults[pinNr]);
pinMode(switchPins[pinNr], OUTPUT);
}
}
void loop()
{
if (!mqttInitialized) {
mqttInit();
return; // Try again in next loop iteration
}
}
void mqttInit()
{
if (!mqtt)
return;
mqtt->onMessage(
std::bind(&UsermodMqttSwitch::onMqttMessage, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4,
std::placeholders::_5, std::placeholders::_6));
mqtt->onConnect(std::bind(&UsermodMqttSwitch::onMqttConnect, this, std::placeholders::_1));
mqttInitialized = true;
}
void onMqttConnect(bool sessionPresent);
void onMqttMessage(char *topic, char *payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total);
void updateState(uint8_t pinNr);
void setState(uint8_t pinNr, bool active)
{
if (pinNr > NUM_SWITCH_PINS)
return;
switchState[pinNr] = active;
digitalWrite((char) switchPins[pinNr], (char) (switchInvert[pinNr] ? !active : active));
updateState(pinNr);
}
};
inline void UsermodMqttSwitch::onMqttConnect(bool sessionPresent)
{
if (mqttDeviceTopic[0] == 0)
return;
for (int pinNr = 0; pinNr < NUM_SWITCH_PINS; pinNr++) {
char buf[128];
StaticJsonDocument<1024> json;
sprintf(buf, "%s Switch %d", serverDescription, pinNr + 1);
json[F("name")] = buf;
sprintf(buf, "%s/switch/%d", mqttDeviceTopic, pinNr);
json["~"] = buf;
strcat(buf, "/set");
mqtt->subscribe(buf, 0);
json[F("stat_t")] = "~/state";
json[F("cmd_t")] = "~/set";
json[F("pl_off")] = F("OFF");
json[F("pl_on")] = F("ON");
char uid[16];
sprintf(uid, "%s_sw%d", escapedMac.c_str(), pinNr);
json[F("unique_id")] = uid;
strcpy(buf, mqttDeviceTopic);
strcat(buf, "/status");
json[F("avty_t")] = buf;
json[F("pl_avail")] = F("online");
json[F("pl_not_avail")] = F("offline");
//TODO: dev
sprintf(buf, "homeassistant/switch/%s/config", uid);
char json_str[1024];
size_t payload_size = serializeJson(json, json_str);
mqtt->publish(buf, 0, true, json_str, payload_size);
updateState(pinNr);
}
}
inline void UsermodMqttSwitch::onMqttMessage(char *topic, char *payload, AsyncMqttClientMessageProperties properties, size_t len, size_t index, size_t total)
{
//Note: Payload is not necessarily null terminated. Check "len" instead.
for (int pinNr = 0; pinNr < NUM_SWITCH_PINS; pinNr++) {
char buf[64];
sprintf(buf, "%s/switch/%d/set", mqttDeviceTopic, pinNr);
if (strcmp(topic, buf) == 0) {
//Any string starting with "ON" is interpreted as ON, everything else as OFF
setState(pinNr, len >= 2 && payload[0] == 'O' && payload[1] == 'N');
break;
}
}
}
inline void UsermodMqttSwitch::updateState(uint8_t pinNr)
{
if (!mqttInitialized)
return;
if (pinNr > NUM_SWITCH_PINS)
return;
char buf[64];
sprintf(buf, "%s/switch/%d/state", mqttDeviceTopic, pinNr);
if (switchState[pinNr]) {
mqtt->publish(buf, 0, false, "ON");
} else {
mqtt->publish(buf, 0, false, "OFF");
}
}

View File

@ -1128,12 +1128,12 @@ uint16_t WS2812FX::mode_rain()
SEGENV.step += FRAMETIME;
if (SEGENV.step > SPEED_FORMULA_L) {
SEGENV.step = 0;
//shift all leds right
uint32_t ctemp = getPixelColor(SEGLEN -1);
for(uint16_t i = SEGLEN -1; i > 0; i--) {
setPixelColor(i, getPixelColor(i-1));
//shift all leds left
uint32_t ctemp = getPixelColor(0);
for(uint16_t i = 0; i < SEGLEN - 1; i++) {
setPixelColor(i, getPixelColor(i+1));
}
setPixelColor(0, ctemp);
setPixelColor(SEGLEN -1, ctemp);
SEGENV.aux0++;
SEGENV.aux1++;
if (SEGENV.aux0 == 0) SEGENV.aux0 = UINT16_MAX;

View File

@ -731,7 +731,7 @@ const char JSON_palette_names[] PROGMEM = R"=====([
"Pastel","Sunset 2","Beech","Vintage","Departure","Landscape","Beach","Sherbet","Hult","Hult 64",
"Drywet","Jul","Grintage","Rewhi","Tertiary","Fire","Icefire","Cyane","Light Pink","Autumn",
"Magenta","Magred","Yelmag","Yelblu","Orange & Teal","Tiamat","April Night","Orangery","C9","Sakura",
"Aurora","Atlantica","C9 2"
"Aurora","Atlantica","C9 2","C9 New"
])=====";
#endif

View File

@ -48,8 +48,8 @@
<a href="https://github.com/Aircoookie/WLED/" target="_blank">WLED</a> version ##VERSION##<!-- Autoreplaced from package.json --><br><br>
<a href="https://github.com/Aircoookie/WLED/wiki/Contributors-&-About" target="_blank">Contributors, dependencies and special thanks</a><br>
A huge thank you to everyone who helped me create WLED!<br><br>
(c) 2016-2019 Christian Schwinne <br>
<i>Licensed under the MIT license</i><br><br>
(c) 2016-2020 Christian Schwinne <br>
<i>Licensed under the <a href="https://github.com/Aircoookie/WLED/blob/master/LICENSE" target="_blank">MIT license</a></i><br><br>
Server message: <span class="sip"> Response error! </span><hr>
<button type="button" onclick="B()">Back</button><button type="submit">Save & Reboot</button>
</form>

View File

@ -360,7 +360,7 @@ HTTP traffic is unencrypted. An attacker in the same network can intercept form
href="https://github.com/Aircoookie/WLED/wiki/Contributors-&-About"
target="_blank">Contributors, dependencies and special thanks</a><br>
A huge thank you to everyone who helped me create WLED!<br><br>
(c) 2016-2019 Christian Schwinne<br><i>Licensed under the MIT license</i><br>
(c) 2016-2020 Christian Schwinne<br><i>Licensed under the <a href="https://github.com/Aircoookie/WLED/blob/master/LICENSE" target="_blank">MIT license</a></i><br>
<br>Server message: <span class="sip">Response error!</span><hr><button
type="button" onclick="B()">Back</button><button type="submit">Save & Reboot
</button></form></body></html>)=====";

View File

@ -338,6 +338,11 @@ void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segme
nl[F("fade")] = (nightlightMode > NL_MODE_SET); //deprecated
nl[F("mode")] = nightlightMode;
nl[F("tbri")] = nightlightTargetBri;
if (nightlightActive) {
nl[F("rem")] = (nightlightDelayMs - (millis() - nightlightStartTime)) / 1000; // seconds remaining
} else {
nl[F("rem")] = -1;
}
JsonObject udpn = root.createNestedObject("udpn");
udpn[F("send")] = notifyDirect;
@ -347,7 +352,7 @@ void serializeState(JsonObject root, bool forPreset, bool includeBri, bool segme
}
root[F("mainseg")] = strip.getMainSegmentId();
JsonArray seg = root.createNestedArray("seg");
for (byte s = 0; s < strip.getMaxSegments(); s++)
{

View File

@ -64,18 +64,40 @@ void onMqttMessage(char* topic, char* payload, AsyncMqttClientMessageProperties
}
DEBUG_PRINTLN(payload);
//no need to check the topic because we only get topics we are subscribed to
size_t topicPrefixLen = strlen(mqttDeviceTopic);
if (strncmp(topic, mqttDeviceTopic, topicPrefixLen) == 0) {
topic += topicPrefixLen;
} else {
size_t topic_prefix_len = strlen(mqttGroupTopic);
if (strncmp(topic, mqttGroupTopic, topicPrefixLen) == 0) {
topic += topicPrefixLen;
} else {
// Topic not used here. Probably a usermod subscribed to this topic.
return;
}
}
if (strstr(topic, "/col"))
//Prefix is stripped from the topic at this point
if (strcmp(topic, "/col") == 0)
{
colorFromDecOrHexString(col, (char*)payload);
colorUpdated(NOTIFIER_CALL_MODE_DIRECT_CHANGE);
} else if (strstr(topic, "/api"))
} else if (strcmp(topic, "/api") == 0)
{
String apireq = "win&";
apireq += (char*)payload;
handleSet(nullptr, apireq);
} else parseMQTTBriPayload(payload);
if (payload[0] == '{') { //JSON API
DynamicJsonDocument doc(JSON_BUFFER_SIZE);
deserializeJson(doc, payload);
deserializeState(doc.as<JsonObject>());
} else { //HTTP API
String apireq = "win&";
apireq += (char*)payload;
handleSet(nullptr, apireq);
}
} else if (strcmp(topic, "") == 0)
{
parseMQTTBriPayload(payload);
}
}

View File

@ -13,7 +13,7 @@
#ifndef PalettesWLED_h
#define PalettesWLED_h
#define GRADIENT_PALETTE_COUNT 40
#define GRADIENT_PALETTE_COUNT 41
const byte ib_jul01_gp[] PROGMEM = {
0, 194, 1, 1,
@ -551,14 +551,14 @@ const byte Orangery_gp[] PROGMEM = {
//inspired by Mark Kriegsman https://gist.github.com/kriegsman/756ea6dcae8e30845b5a
const byte C9_gp[] PROGMEM = {
0, 255, 5, 0, //red
60, 255, 5, 0,
60, 196, 57, 2, //amber (start 61?)
120, 196, 57, 2,
120, 6, 126, 2, //green (start 126?)
180, 6, 126, 2,
180, 4, 30, 114, //blue (start 191?)
255, 4, 30, 114};
0, 184, 4, 0, //red
60, 184, 4, 0,
65, 144, 44, 2, //amber
125, 144, 44, 2,
130, 4, 96, 2, //green
190, 4, 96, 2,
195, 7, 7, 88, //blue
255, 7, 7, 88};
const byte Sakura_gp[] PROGMEM = {
0, 196, 19, 10,
@ -594,6 +594,17 @@ const byte Atlantica_gp[] PROGMEM = {
180, 196, 57, 2,
180, 137, 85, 2, //yellow
255, 137, 85, 2};
//C9, but brighter and with a less purple blue
const byte C9_new_gp[] PROGMEM = {
0, 255, 5, 0, //red
60, 255, 5, 0,
60, 196, 57, 2, //amber (start 61?)
120, 196, 57, 2,
120, 6, 126, 2, //green (start 126?)
180, 6, 126, 2,
180, 4, 30, 114, //blue (start 191?)
255, 4, 30, 114};
// Single array of defined cpt-city color palettes.
@ -640,7 +651,8 @@ const byte* const gGradientPalettes[] PROGMEM = {
Sakura_gp, //49-36 Sakura
Aurora_gp, //50-37 Aurora
Atlantica_gp, //51-38 Atlantica
C9_2_gp //52-39 C9 2
C9_2_gp, //52-39 C9 2
C9_new_gp //53-40 C9 New
};
#endif

View File

@ -8,7 +8,7 @@
*/
// version code in format yymmddb (b = daily build)
#define VERSION 2011092
#define VERSION 2011121
// ESP8266-01 (blue) got too little storage space to work with WLED. 0.10.2 is the last release supporting this unit.