Added CL= and C2= API calls to set HEX or DEC RGB or WRGB color

Started to add MQTT support
Pre server and init split-up
This commit is contained in:
cschwinne 2018-09-28 23:53:51 +02:00
parent 5f59487a88
commit dbd6f134c1
11 changed files with 932 additions and 21 deletions

View File

@ -38,6 +38,7 @@
Modified for WLED Modified for WLED
*/ */
#include "WS2812FX.h" #include "WS2812FX.h"
#include "FastLED.h" #include "FastLED.h"
#include "palettes.h"; #include "palettes.h";

View File

@ -0,0 +1,20 @@
Copyright (c) 2008-2015 Nicholas O'Leary
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.

View File

@ -0,0 +1,601 @@
/*
PubSubClient.cpp - A simple client for MQTT.
Nick O'Leary
http://knolleary.net
*/
#include "PubSubClient.h"
#include "Arduino.h"
PubSubClient::PubSubClient() {
this->_state = MQTT_DISCONNECTED;
this->_client = NULL;
this->stream = NULL;
setCallback(NULL);
}
PubSubClient::PubSubClient(Client& client) {
this->_state = MQTT_DISCONNECTED;
setClient(client);
this->stream = NULL;
}
PubSubClient::PubSubClient(IPAddress addr, uint16_t port, Client& client) {
this->_state = MQTT_DISCONNECTED;
setServer(addr, port);
setClient(client);
this->stream = NULL;
}
PubSubClient::PubSubClient(IPAddress addr, uint16_t port, Client& client, Stream& stream) {
this->_state = MQTT_DISCONNECTED;
setServer(addr,port);
setClient(client);
setStream(stream);
}
PubSubClient::PubSubClient(IPAddress addr, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client) {
this->_state = MQTT_DISCONNECTED;
setServer(addr, port);
setCallback(callback);
setClient(client);
this->stream = NULL;
}
PubSubClient::PubSubClient(IPAddress addr, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client, Stream& stream) {
this->_state = MQTT_DISCONNECTED;
setServer(addr,port);
setCallback(callback);
setClient(client);
setStream(stream);
}
PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, Client& client) {
this->_state = MQTT_DISCONNECTED;
setServer(ip, port);
setClient(client);
this->stream = NULL;
}
PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, Client& client, Stream& stream) {
this->_state = MQTT_DISCONNECTED;
setServer(ip,port);
setClient(client);
setStream(stream);
}
PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client) {
this->_state = MQTT_DISCONNECTED;
setServer(ip, port);
setCallback(callback);
setClient(client);
this->stream = NULL;
}
PubSubClient::PubSubClient(uint8_t *ip, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client, Stream& stream) {
this->_state = MQTT_DISCONNECTED;
setServer(ip,port);
setCallback(callback);
setClient(client);
setStream(stream);
}
PubSubClient::PubSubClient(const char* domain, uint16_t port, Client& client) {
this->_state = MQTT_DISCONNECTED;
setServer(domain,port);
setClient(client);
this->stream = NULL;
}
PubSubClient::PubSubClient(const char* domain, uint16_t port, Client& client, Stream& stream) {
this->_state = MQTT_DISCONNECTED;
setServer(domain,port);
setClient(client);
setStream(stream);
}
PubSubClient::PubSubClient(const char* domain, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client) {
this->_state = MQTT_DISCONNECTED;
setServer(domain,port);
setCallback(callback);
setClient(client);
this->stream = NULL;
}
PubSubClient::PubSubClient(const char* domain, uint16_t port, MQTT_CALLBACK_SIGNATURE, Client& client, Stream& stream) {
this->_state = MQTT_DISCONNECTED;
setServer(domain,port);
setCallback(callback);
setClient(client);
setStream(stream);
}
boolean PubSubClient::connect(const char *id) {
return connect(id,NULL,NULL,0,0,0,0);
}
boolean PubSubClient::connect(const char *id, const char *user, const char *pass) {
return connect(id,user,pass,0,0,0,0);
}
boolean PubSubClient::connect(const char *id, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage) {
return connect(id,NULL,NULL,willTopic,willQos,willRetain,willMessage);
}
boolean PubSubClient::connect(const char *id, const char *user, const char *pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage) {
if (!connected()) {
int result = 0;
if (domain != NULL) {
result = _client->connect(this->domain, this->port);
} else {
result = _client->connect(this->ip, this->port);
}
if (result == 1) {
nextMsgId = 1;
// Leave room in the buffer for header and variable length field
uint16_t length = 5;
unsigned int j;
#if MQTT_VERSION == MQTT_VERSION_3_1
uint8_t d[9] = {0x00,0x06,'M','Q','I','s','d','p', MQTT_VERSION};
#define MQTT_HEADER_VERSION_LENGTH 9
#elif MQTT_VERSION == MQTT_VERSION_3_1_1
uint8_t d[7] = {0x00,0x04,'M','Q','T','T',MQTT_VERSION};
#define MQTT_HEADER_VERSION_LENGTH 7
#endif
for (j = 0;j<MQTT_HEADER_VERSION_LENGTH;j++) {
buffer[length++] = d[j];
}
uint8_t v;
if (willTopic) {
v = 0x06|(willQos<<3)|(willRetain<<5);
} else {
v = 0x02;
}
if(user != NULL) {
v = v|0x80;
if(pass != NULL) {
v = v|(0x80>>1);
}
}
buffer[length++] = v;
buffer[length++] = ((MQTT_KEEPALIVE) >> 8);
buffer[length++] = ((MQTT_KEEPALIVE) & 0xFF);
length = writeString(id,buffer,length);
if (willTopic) {
length = writeString(willTopic,buffer,length);
length = writeString(willMessage,buffer,length);
}
if(user != NULL) {
length = writeString(user,buffer,length);
if(pass != NULL) {
length = writeString(pass,buffer,length);
}
}
write(MQTTCONNECT,buffer,length-5);
lastInActivity = lastOutActivity = millis();
while (!_client->available()) {
unsigned long t = millis();
if (t-lastInActivity >= ((int32_t) MQTT_SOCKET_TIMEOUT*1000UL)) {
_state = MQTT_CONNECTION_TIMEOUT;
_client->stop();
return false;
}
}
uint8_t llen;
uint16_t len = readPacket(&llen);
if (len == 4) {
if (buffer[3] == 0) {
lastInActivity = millis();
pingOutstanding = false;
_state = MQTT_CONNECTED;
return true;
} else {
_state = buffer[3];
}
}
_client->stop();
} else {
_state = MQTT_CONNECT_FAILED;
}
return false;
}
return true;
}
// reads a byte into result
boolean PubSubClient::readByte(uint8_t * result) {
uint32_t previousMillis = millis();
while(!_client->available()) {
uint32_t currentMillis = millis();
if(currentMillis - previousMillis >= ((int32_t) MQTT_SOCKET_TIMEOUT * 1000)){
return false;
}
}
*result = _client->read();
return true;
}
// reads a byte into result[*index] and increments index
boolean PubSubClient::readByte(uint8_t * result, uint16_t * index){
uint16_t current_index = *index;
uint8_t * write_address = &(result[current_index]);
if(readByte(write_address)){
*index = current_index + 1;
return true;
}
return false;
}
uint16_t PubSubClient::readPacket(uint8_t* lengthLength) {
uint16_t len = 0;
if(!readByte(buffer, &len)) return 0;
bool isPublish = (buffer[0]&0xF0) == MQTTPUBLISH;
uint32_t multiplier = 1;
uint16_t length = 0;
uint8_t digit = 0;
uint16_t skip = 0;
uint8_t start = 0;
do {
if (len == 6) {
// Invalid remaining length encoding - kill the connection
_state = MQTT_DISCONNECTED;
_client->stop();
return 0;
}
if(!readByte(&digit)) return 0;
buffer[len++] = digit;
length += (digit & 127) * multiplier;
multiplier *= 128;
} while ((digit & 128) != 0);
*lengthLength = len-1;
if (isPublish) {
// Read in topic length to calculate bytes to skip over for Stream writing
if(!readByte(buffer, &len)) return 0;
if(!readByte(buffer, &len)) return 0;
skip = (buffer[*lengthLength+1]<<8)+buffer[*lengthLength+2];
start = 2;
if (buffer[0]&MQTTQOS1) {
// skip message id
skip += 2;
}
}
for (uint16_t i = start;i<length;i++) {
if(!readByte(&digit)) return 0;
if (this->stream) {
if (isPublish && len-*lengthLength-2>skip) {
this->stream->write(digit);
}
}
if (len < MQTT_MAX_PACKET_SIZE) {
buffer[len] = digit;
}
len++;
}
if (!this->stream && len > MQTT_MAX_PACKET_SIZE) {
len = 0; // This will cause the packet to be ignored.
}
return len;
}
boolean PubSubClient::loop() {
if (connected()) {
unsigned long t = millis();
if ((t - lastInActivity > MQTT_KEEPALIVE*1000UL) || (t - lastOutActivity > MQTT_KEEPALIVE*1000UL)) {
if (pingOutstanding) {
this->_state = MQTT_CONNECTION_TIMEOUT;
_client->stop();
return false;
} else {
buffer[0] = MQTTPINGREQ;
buffer[1] = 0;
_client->write(buffer,2);
lastOutActivity = t;
lastInActivity = t;
pingOutstanding = true;
}
}
if (_client->available()) {
uint8_t llen;
uint16_t len = readPacket(&llen);
uint16_t msgId = 0;
uint8_t *payload;
if (len > 0) {
lastInActivity = t;
uint8_t type = buffer[0]&0xF0;
if (type == MQTTPUBLISH) {
if (callback) {
uint16_t tl = (buffer[llen+1]<<8)+buffer[llen+2]; /* topic length in bytes */
memmove(buffer+llen+2,buffer+llen+3,tl); /* move topic inside buffer 1 byte to front */
buffer[llen+2+tl] = 0; /* end the topic as a 'C' string with \x00 */
char *topic = (char*) buffer+llen+2;
// make sure payload can be interpreted as 'C' string
buffer[(len < MQTT_MAX_PACKET_SIZE) ? len -1 : MQTT_MAX_PACKET_SIZE -1] = 0;
// msgId only present for QOS>0
if ((buffer[0]&0x06) == MQTTQOS1) {
msgId = (buffer[llen+3+tl]<<8)+buffer[llen+3+tl+1];
payload = buffer+llen+3+tl+2;
callback(topic,payload,len-llen-3-tl-2);
buffer[0] = MQTTPUBACK;
buffer[1] = 2;
buffer[2] = (msgId >> 8);
buffer[3] = (msgId & 0xFF);
_client->write(buffer,4);
lastOutActivity = t;
} else {
payload = buffer+llen+3+tl;
callback(topic,payload,len-llen-3-tl);
}
}
} else if (type == MQTTPINGREQ) {
buffer[0] = MQTTPINGRESP;
buffer[1] = 0;
_client->write(buffer,2);
} else if (type == MQTTPINGRESP) {
pingOutstanding = false;
}
} else if (!connected()) {
// readPacket has closed the connection
return false;
}
}
return true;
}
return false;
}
boolean PubSubClient::publish(const char* topic, const char* payload) {
return publish(topic,(const uint8_t*)payload,strlen(payload),false);
}
boolean PubSubClient::publish(const char* topic, const char* payload, boolean retained) {
return publish(topic,(const uint8_t*)payload,strlen(payload),retained);
}
boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigned int plength) {
return publish(topic, payload, plength, false);
}
boolean PubSubClient::publish(const char* topic, const uint8_t* payload, unsigned int plength, boolean retained) {
if (connected()) {
if (MQTT_MAX_PACKET_SIZE < 5 + 2+strlen(topic) + plength) {
// Too long
return false;
}
// Leave room in the buffer for header and variable length field
uint16_t length = 5;
length = writeString(topic,buffer,length);
uint16_t i;
for (i=0;i<plength;i++) {
buffer[length++] = payload[i];
}
uint8_t header = MQTTPUBLISH;
if (retained) {
header |= 1;
}
return write(header,buffer,length-5);
}
return false;
}
boolean PubSubClient::publish_P(const char* topic, const uint8_t* payload, unsigned int plength, boolean retained) {
uint8_t llen = 0;
uint8_t digit;
unsigned int rc = 0;
uint16_t tlen;
unsigned int pos = 0;
unsigned int i;
uint8_t header;
unsigned int len;
if (!connected()) {
return false;
}
tlen = strlen(topic);
header = MQTTPUBLISH;
if (retained) {
header |= 1;
}
buffer[pos++] = header;
len = plength + 2 + tlen;
do {
digit = len % 128;
len = len / 128;
if (len > 0) {
digit |= 0x80;
}
buffer[pos++] = digit;
llen++;
} while(len>0);
pos = writeString(topic,buffer,pos);
rc += _client->write(buffer,pos);
for (i=0;i<plength;i++) {
rc += _client->write((char)pgm_read_byte_near(payload + i));
}
lastOutActivity = millis();
return rc == tlen + 4 + plength;
}
boolean PubSubClient::write(uint8_t header, uint8_t* buf, uint16_t length) {
uint8_t lenBuf[4];
uint8_t llen = 0;
uint8_t digit;
uint8_t pos = 0;
uint16_t rc;
uint16_t len = length;
do {
digit = len % 128;
len = len / 128;
if (len > 0) {
digit |= 0x80;
}
lenBuf[pos++] = digit;
llen++;
} while(len>0);
buf[4-llen] = header;
for (int i=0;i<llen;i++) {
buf[5-llen+i] = lenBuf[i];
}
#ifdef MQTT_MAX_TRANSFER_SIZE
uint8_t* writeBuf = buf+(4-llen);
uint16_t bytesRemaining = length+1+llen; //Match the length type
uint8_t bytesToWrite;
boolean result = true;
while((bytesRemaining > 0) && result) {
bytesToWrite = (bytesRemaining > MQTT_MAX_TRANSFER_SIZE)?MQTT_MAX_TRANSFER_SIZE:bytesRemaining;
rc = _client->write(writeBuf,bytesToWrite);
result = (rc == bytesToWrite);
bytesRemaining -= rc;
writeBuf += rc;
}
return result;
#else
rc = _client->write(buf+(4-llen),length+1+llen);
lastOutActivity = millis();
return (rc == 1+llen+length);
#endif
}
boolean PubSubClient::subscribe(const char* topic) {
return subscribe(topic, 0);
}
boolean PubSubClient::subscribe(const char* topic, uint8_t qos) {
if (qos > 1) {
return false;
}
if (MQTT_MAX_PACKET_SIZE < 9 + strlen(topic)) {
// Too long
return false;
}
if (connected()) {
// Leave room in the buffer for header and variable length field
uint16_t length = 5;
nextMsgId++;
if (nextMsgId == 0) {
nextMsgId = 1;
}
buffer[length++] = (nextMsgId >> 8);
buffer[length++] = (nextMsgId & 0xFF);
length = writeString((char*)topic, buffer,length);
buffer[length++] = qos;
return write(MQTTSUBSCRIBE|MQTTQOS1,buffer,length-5);
}
return false;
}
boolean PubSubClient::unsubscribe(const char* topic) {
if (MQTT_MAX_PACKET_SIZE < 9 + strlen(topic)) {
// Too long
return false;
}
if (connected()) {
uint16_t length = 5;
nextMsgId++;
if (nextMsgId == 0) {
nextMsgId = 1;
}
buffer[length++] = (nextMsgId >> 8);
buffer[length++] = (nextMsgId & 0xFF);
length = writeString(topic, buffer,length);
return write(MQTTUNSUBSCRIBE|MQTTQOS1,buffer,length-5);
}
return false;
}
void PubSubClient::disconnect() {
buffer[0] = MQTTDISCONNECT;
buffer[1] = 0;
_client->write(buffer,2);
_state = MQTT_DISCONNECTED;
_client->stop();
lastInActivity = lastOutActivity = millis();
}
uint16_t PubSubClient::writeString(const char* string, uint8_t* buf, uint16_t pos) {
const char* idp = string;
uint16_t i = 0;
pos += 2;
while (*idp) {
buf[pos++] = *idp++;
i++;
}
buf[pos-i-2] = (i >> 8);
buf[pos-i-1] = (i & 0xFF);
return pos;
}
boolean PubSubClient::connected() {
boolean rc;
if (_client == NULL ) {
rc = false;
} else {
rc = (int)_client->connected();
if (!rc) {
if (this->_state == MQTT_CONNECTED) {
this->_state = MQTT_CONNECTION_LOST;
_client->flush();
_client->stop();
}
}
}
return rc;
}
PubSubClient& PubSubClient::setServer(uint8_t * ip, uint16_t port) {
IPAddress addr(ip[0],ip[1],ip[2],ip[3]);
return setServer(addr,port);
}
PubSubClient& PubSubClient::setServer(IPAddress ip, uint16_t port) {
this->ip = ip;
this->port = port;
this->domain = NULL;
return *this;
}
PubSubClient& PubSubClient::setServer(const char * domain, uint16_t port) {
this->domain = domain;
this->port = port;
return *this;
}
PubSubClient& PubSubClient::setCallback(MQTT_CALLBACK_SIGNATURE) {
this->callback = callback;
return *this;
}
PubSubClient& PubSubClient::setClient(Client& client){
this->_client = &client;
return *this;
}
PubSubClient& PubSubClient::setStream(Stream& stream){
this->stream = &stream;
return *this;
}
int PubSubClient::state() {
return this->_state;
}

View File

@ -0,0 +1,144 @@
/*
PubSubClient.h - A simple client for MQTT.
Nick O'Leary
http://knolleary.net
*/
#ifndef PubSubClient_h
#define PubSubClient_h
#include <Arduino.h>
#include "IPAddress.h"
#include "Client.h"
#include "Stream.h"
#define MQTT_VERSION_3_1 3
#define MQTT_VERSION_3_1_1 4
// MQTT_VERSION : Pick the version
//#define MQTT_VERSION MQTT_VERSION_3_1
#ifndef MQTT_VERSION
#define MQTT_VERSION MQTT_VERSION_3_1_1
#endif
// MQTT_MAX_PACKET_SIZE : Maximum packet size
#ifndef MQTT_MAX_PACKET_SIZE
#define MQTT_MAX_PACKET_SIZE 128
#endif
// MQTT_KEEPALIVE : keepAlive interval in Seconds
#ifndef MQTT_KEEPALIVE
#define MQTT_KEEPALIVE 15
#endif
// MQTT_SOCKET_TIMEOUT: socket timeout interval in Seconds
#ifndef MQTT_SOCKET_TIMEOUT
#define MQTT_SOCKET_TIMEOUT 15
#endif
// MQTT_MAX_TRANSFER_SIZE : limit how much data is passed to the network client
// in each write call. Needed for the Arduino Wifi Shield. Leave undefined to
// pass the entire MQTT packet in each write call.
//#define MQTT_MAX_TRANSFER_SIZE 80
// Possible values for client.state()
#define MQTT_CONNECTION_TIMEOUT -4
#define MQTT_CONNECTION_LOST -3
#define MQTT_CONNECT_FAILED -2
#define MQTT_DISCONNECTED -1
#define MQTT_CONNECTED 0
#define MQTT_CONNECT_BAD_PROTOCOL 1
#define MQTT_CONNECT_BAD_CLIENT_ID 2
#define MQTT_CONNECT_UNAVAILABLE 3
#define MQTT_CONNECT_BAD_CREDENTIALS 4
#define MQTT_CONNECT_UNAUTHORIZED 5
#define MQTTCONNECT 1 << 4 // Client request to connect to Server
#define MQTTCONNACK 2 << 4 // Connect Acknowledgment
#define MQTTPUBLISH 3 << 4 // Publish message
#define MQTTPUBACK 4 << 4 // Publish Acknowledgment
#define MQTTPUBREC 5 << 4 // Publish Received (assured delivery part 1)
#define MQTTPUBREL 6 << 4 // Publish Release (assured delivery part 2)
#define MQTTPUBCOMP 7 << 4 // Publish Complete (assured delivery part 3)
#define MQTTSUBSCRIBE 8 << 4 // Client Subscribe request
#define MQTTSUBACK 9 << 4 // Subscribe Acknowledgment
#define MQTTUNSUBSCRIBE 10 << 4 // Client Unsubscribe request
#define MQTTUNSUBACK 11 << 4 // Unsubscribe Acknowledgment
#define MQTTPINGREQ 12 << 4 // PING Request
#define MQTTPINGRESP 13 << 4 // PING Response
#define MQTTDISCONNECT 14 << 4 // Client is Disconnecting
#define MQTTReserved 15 << 4 // Reserved
#define MQTTQOS0 (0 << 1)
#define MQTTQOS1 (1 << 1)
#define MQTTQOS2 (2 << 1)
#ifdef ESP8266
#include <functional>
#define MQTT_CALLBACK_SIGNATURE std::function<void(char*, uint8_t*, unsigned int)> callback
#else
#define MQTT_CALLBACK_SIGNATURE void (*callback)(char*, uint8_t*, unsigned int)
#endif
class PubSubClient {
private:
Client* _client;
uint8_t buffer[MQTT_MAX_PACKET_SIZE];
uint16_t nextMsgId;
unsigned long lastOutActivity;
unsigned long lastInActivity;
bool pingOutstanding;
MQTT_CALLBACK_SIGNATURE;
uint16_t readPacket(uint8_t*);
boolean readByte(uint8_t * result);
boolean readByte(uint8_t * result, uint16_t * index);
boolean write(uint8_t header, uint8_t* buf, uint16_t length);
uint16_t writeString(const char* string, uint8_t* buf, uint16_t pos);
IPAddress ip;
const char* domain;
uint16_t port;
Stream* stream;
int _state;
public:
PubSubClient();
PubSubClient(Client& client);
PubSubClient(IPAddress, uint16_t, Client& client);
PubSubClient(IPAddress, uint16_t, Client& client, Stream&);
PubSubClient(IPAddress, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client);
PubSubClient(IPAddress, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client, Stream&);
PubSubClient(uint8_t *, uint16_t, Client& client);
PubSubClient(uint8_t *, uint16_t, Client& client, Stream&);
PubSubClient(uint8_t *, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client);
PubSubClient(uint8_t *, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client, Stream&);
PubSubClient(const char*, uint16_t, Client& client);
PubSubClient(const char*, uint16_t, Client& client, Stream&);
PubSubClient(const char*, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client);
PubSubClient(const char*, uint16_t, MQTT_CALLBACK_SIGNATURE,Client& client, Stream&);
PubSubClient& setServer(IPAddress ip, uint16_t port);
PubSubClient& setServer(uint8_t * ip, uint16_t port);
PubSubClient& setServer(const char * domain, uint16_t port);
PubSubClient& setCallback(MQTT_CALLBACK_SIGNATURE);
PubSubClient& setClient(Client& client);
PubSubClient& setStream(Stream& stream);
boolean connect(const char* id);
boolean connect(const char* id, const char* user, const char* pass);
boolean connect(const char* id, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage);
boolean connect(const char* id, const char* user, const char* pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage);
void disconnect();
boolean publish(const char* topic, const char* payload);
boolean publish(const char* topic, const char* payload, boolean retained);
boolean publish(const char* topic, const uint8_t * payload, unsigned int plength);
boolean publish(const char* topic, const uint8_t * payload, unsigned int plength, boolean retained);
boolean publish_P(const char* topic, const uint8_t * payload, unsigned int plength, boolean retained);
boolean subscribe(const char* topic);
boolean subscribe(const char* topic, uint8_t qos);
boolean unsubscribe(const char* topic);
boolean loop();
boolean connected();
int state();
};
#endif

View File

@ -35,16 +35,17 @@
#include "src/dependencies/time/Time.h" #include "src/dependencies/time/Time.h"
#include "src/dependencies/time/TimeLib.h" #include "src/dependencies/time/TimeLib.h"
#include "src/dependencies/timezone/Timezone.h" #include "src/dependencies/timezone/Timezone.h"
#include "src/dependencies/blynk/BlynkSimpleEsp.h"
#include "src/dependencies/e131/E131.h"
#include "src/dependencies/pubsubclient/PubSubClient.h"
#include "htmls00.h" #include "htmls00.h"
#include "htmls01.h" #include "htmls01.h"
#include "htmls02.h" #include "htmls02.h"
#include "WS2812FX.h" #include "WS2812FX.h"
#include "src/dependencies/blynk/BlynkSimpleEsp.h"
#include "src/dependencies/e131/E131.h"
//version code in format yymmddb (b = daily build) //version code in format yymmddb (b = daily build)
#define VERSION 1809222 #define VERSION 1809281
char versionString[] = "0.8.0-a"; char versionString[] = "0.8.0-a";
@ -160,6 +161,10 @@ bool e131Enabled = true; //settings for E1.31 (sACN) protoc
uint16_t e131Universe = 1; uint16_t e131Universe = 1;
bool e131Multicast = false; bool e131Multicast = false;
char mqttTopic0[33] = ""; //main MQTT topic (individual per device, default is wled/mac)
char mqttTopic1[33] = "wled/all"; //second MQTT topic (for example to group devices)
char mqttServer[33] = "37.187.106.16"; //both domains and IPs should work (no SSL) 37.187.106.16
bool huePollingEnabled = false; //poll hue bridge for light state bool huePollingEnabled = false; //poll hue bridge for light state
uint16_t huePollIntervalMs = 2500; //low values (< 1sec) may cause lag but offer quicker response uint16_t huePollIntervalMs = 2500; //low values (< 1sec) may cause lag but offer quicker response
char hueApiKey[65] = "api"; //key token will be obtained from bridge char hueApiKey[65] = "api"; //key token will be obtained from bridge
@ -324,13 +329,17 @@ bool realtimeActive = false;
IPAddress realtimeIP = (0,0,0,0); IPAddress realtimeIP = (0,0,0,0);
unsigned long realtimeTimeout = 0; unsigned long realtimeTimeout = 0;
//mqtt
bool mqttInit = false;
long lastMQTTReconnectAttempt = 0;
//auxiliary debug pin //auxiliary debug pin
byte auxTime = 0; byte auxTime = 0;
unsigned long auxStartTime = 0; unsigned long auxStartTime = 0;
bool auxActive = false, auxActiveBefore = false; bool auxActive = false, auxActiveBefore = false;
//alexa udp //alexa udp
WiFiUDP UDP; WiFiUDP alexaUDP;
IPAddress ipMulti(239, 255, 255, 250); IPAddress ipMulti(239, 255, 255, 250);
unsigned int portMulti = 1900; unsigned int portMulti = 1900;
String escapedMac; String escapedMac;
@ -360,6 +369,9 @@ WebServer server(80);
ESP8266WebServer server(80); ESP8266WebServer server(80);
#endif #endif
HTTPClient hueClient; HTTPClient hueClient;
WiFiClient mqttTCPClient;
PubSubClient mqtt(mqttTCPClient);
ESP8266HTTPUpdateServer httpUpdater; ESP8266HTTPUpdateServer httpUpdater;
//udp interface objects //udp interface objects
@ -465,6 +477,9 @@ void loop() {
if (aOtaEnabled) ArduinoOTA.handle(); if (aOtaEnabled) ArduinoOTA.handle();
handleAlexa(); handleAlexa();
handleOverlays(); handleOverlays();
yield();
handleMQTT();
if (!realtimeActive) //block stuff if WARLS/Adalight is enabled if (!realtimeActive) //block stuff if WARLS/Adalight is enabled
{ {

View File

@ -2,7 +2,7 @@
* Sending XML status files to client * Sending XML status files to client
*/ */
void XML_response() void XML_response(bool isHTTP)
{ {
olen = 0; olen = 0;
oappend("<?xml version = \"1.0\" ?><vs><ac>"); oappend("<?xml version = \"1.0\" ?><vs><ac>");
@ -52,7 +52,7 @@ void XML_response()
oappend("</md><ds>"); oappend("</md><ds>");
oappend(serverDescription); oappend(serverDescription);
oappend("</ds></vs>"); oappend("</ds></vs>");
server.send(200, "text/xml", obuf); if (isHTTP) server.send(200, "text/xml", obuf);
} }
void sappend(char stype, char* key, int val) //append a setting to string buffer void sappend(char stype, char* key, int val) //append a setting to string buffer

View File

@ -101,6 +101,7 @@ void handleSettingsSet(byte subPage)
fadeTransition = server.hasArg("TF"); fadeTransition = server.hasArg("TF");
t = server.arg("TD").toInt(); t = server.arg("TD").toInt();
if (t > 0) transitionDelay = t; if (t > 0) transitionDelay = t;
transitionDelayDefault = t;
strip.paletteFade = server.hasArg("PF"); strip.paletteFade = server.hasArg("PF");
enableSecTransition = server.hasArg("T2"); enableSecTransition = server.hasArg("T2");
@ -318,7 +319,7 @@ bool handleSet(String req)
} }
pos = req.indexOf("IN"); pos = req.indexOf("IN");
if (pos < 1) XML_response(); if (pos < 1) XML_response(true);
return true; return true;
//if you save a macro in one request, other commands in that request are ignored due to unwanted behavior otherwise //if you save a macro in one request, other commands in that request are ignored due to unwanted behavior otherwise
} }
@ -383,6 +384,16 @@ bool handleSet(String req)
whiteSec = req.substring(pos + 3).toInt(); whiteSec = req.substring(pos + 3).toInt();
} }
//set color from HEX or 32bit DEC
pos = req.indexOf("CL=");
if (pos > 0) {
colorFromDecOrHexString(col, &white, (char*)req.substring(pos + 3).c_str());
}
pos = req.indexOf("C2=");
if (pos > 0) {
colorFromDecOrHexString(colSec, &whiteSec, (char*)req.substring(pos + 3).c_str());
}
//set 2nd to white //set 2nd to white
pos = req.indexOf("SW"); pos = req.indexOf("SW");
if (pos > 0) { if (pos > 0) {
@ -718,7 +729,7 @@ bool handleSet(String req)
//internal call, does not send XML response //internal call, does not send XML response
pos = req.indexOf("IN"); pos = req.indexOf("IN");
if (pos < 1) XML_response(); if (pos < 1) XML_response(true);
//do not send UDP notifications this time //do not send UDP notifications this time
pos = req.indexOf("NN"); pos = req.indexOf("NN");
if (pos > 0) if (pos > 0)

View File

@ -56,6 +56,10 @@ void wledInit()
dnsServer.start(53, "*", WiFi.softAPIP()); dnsServer.start(53, "*", WiFi.softAPIP());
dnsActive = true; dnsActive = true;
} }
prepareIds(); //UUID from MAC (for Alexa and MQTT)
if (mqttTopic0[0] == 0) strcpy(mqttTopic0, strcat("wled/", escapedMac.c_str()));
if (!initLedsLast) strip.service(); if (!initLedsLast) strip.service();
//SERVER INIT //SERVER INIT
//settings page //settings page
@ -264,6 +268,7 @@ void wledInit()
{ {
initBlynk(blynkApiKey); initBlynk(blynkApiKey);
initE131(); initE131();
mqttInit = initMQTT();
} }
if (initLedsLast) initStrip(); if (initLedsLast) initStrip();

View File

@ -10,8 +10,6 @@ void alexaInit()
{ {
if (alexaEnabled && WiFi.status() == WL_CONNECTED) if (alexaEnabled && WiFi.status() == WL_CONNECTED)
{ {
prepareIds();
udpConnected = connectUDP(); udpConnected = connectUDP();
if (udpConnected) alexaInitPages(); if (udpConnected) alexaInitPages();
@ -24,10 +22,10 @@ void handleAlexa()
{ {
if(udpConnected){ if(udpConnected){
// if theres data available, read a packet // if theres data available, read a packet
int packetSize = UDP.parsePacket(); int packetSize = alexaUDP.parsePacket();
if(packetSize>0) { if(packetSize>0) {
IPAddress remote = UDP.remoteIP(); IPAddress remote = alexaUDP.remoteIP();
int len = UDP.read(obuf, 254); int len = alexaUDP.read(obuf, 254);
if (len > 0) { if (len > 0) {
obuf[len] = 0; obuf[len] = 0;
} }
@ -98,9 +96,9 @@ void prepareIds() {
void respondToSearch() { void respondToSearch() {
DEBUG_PRINTLN(""); DEBUG_PRINTLN("");
DEBUG_PRINT("Send resp to "); DEBUG_PRINT("Send resp to ");
DEBUG_PRINTLN(UDP.remoteIP()); DEBUG_PRINTLN(alexaUDP.remoteIP());
DEBUG_PRINT("Port : "); DEBUG_PRINT("Port : ");
DEBUG_PRINTLN(UDP.remotePort()); DEBUG_PRINTLN(alexaUDP.remotePort());
IPAddress localIP = WiFi.localIP(); IPAddress localIP = WiFi.localIP();
char s[16]; char s[16];
@ -124,13 +122,13 @@ void respondToSearch() {
oappend("::upnp:rootdevice\r\n" // _uuid::_deviceType oappend("::upnp:rootdevice\r\n" // _uuid::_deviceType
"\r\n"); "\r\n");
UDP.beginPacket(UDP.remoteIP(), UDP.remotePort()); alexaUDP.beginPacket(alexaUDP.remoteIP(), alexaUDP.remotePort());
#ifdef ARDUINO_ARCH_ESP32 #ifdef ARDUINO_ARCH_ESP32
UDP.write((byte*)obuf, olen); alexaUDP.write((byte*)obuf, olen);
#else #else
UDP.write(obuf); alexaUDP.write(obuf);
#endif #endif
UDP.endPacket(); alexaUDP.endPacket();
DEBUG_PRINTLN("Response sent!"); DEBUG_PRINTLN("Response sent!");
} }
@ -276,9 +274,9 @@ bool connectUDP(){
DEBUG_PRINTLN("Con UDP"); DEBUG_PRINTLN("Con UDP");
#ifdef ARDUINO_ARCH_ESP32 #ifdef ARDUINO_ARCH_ESP32
if(UDP.beginMulticast(ipMulti, portMulti)) if(alexaUDP.beginMulticast(ipMulti, portMulti))
#else #else
if(UDP.beginMulticast(WiFi.localIP(), ipMulti, portMulti)) if(alexaUDP.beginMulticast(WiFi.localIP(), ipMulti, portMulti))
#endif #endif
{ {
DEBUG_PRINTLN("Con success"); DEBUG_PRINTLN("Con success");

View File

@ -106,6 +106,26 @@ void colorXYtoRGB(float x, float y, byte* rgb) //coordinates to rgb (https://www
rgb[2] = 255.0*b; rgb[2] = 255.0*b;
} }
void colorFromDecOrHexString(byte* rgb, byte* wht, char* in)
{
if (in[0] == 0) return;
char first = in[0];
uint32_t c = 0;
if (first == '#' || first == 'h' || first == 'H') //is HEX encoded
{
c = strtoul(in +1, NULL, 16);
} else
{
c = strtoul(in, NULL, 10);
}
*wht = (c >> 24) & 0xFF;
rgb[0] = (c >> 16) & 0xFF;
rgb[1] = (c >> 8) & 0xFF;
rgb[2] = c & 0xFF;
}
void colorRGBtoXY(byte* rgb, float* xy) //rgb to coordinates (https://www.developers.meethue.com/documentation/color-conversions-rgb-xy) void colorRGBtoXY(byte* rgb, float* xy) //rgb to coordinates (https://www.developers.meethue.com/documentation/color-conversions-rgb-xy)
{ {
float X = rgb[0] * 0.664511f + rgb[1] * 0.154324f + rgb[2] * 0.162028f; float X = rgb[0] * 0.664511f + rgb[1] * 0.154324f + rgb[2] * 0.162028f;

96
wled00/wled17_mqtt.ino Normal file
View File

@ -0,0 +1,96 @@
/*
* MQTT communication protocol for home automation
*/
void callbackMQTT(char* topic, byte* payload, unsigned int length) {
if (strcmp(topic, mqttTopic0) == 0 ||
strcmp(topic, mqttTopic1) == 0)
{
if (strcmp((char*)payload, "ON") == 0) {bri = briLast;}
else if (strcmp((char*)payload, "T" ) == 0) {handleSet("win&T=2");}
else {
uint8_t in = strtoul((char*)payload, NULL, 10);
if (in == 0 && bri > 0) briLast = bri;
bri = in;
}
colorUpdated(1);
return;
}
if (strcmp(topic, strcat(mqttTopic0, "/col")) == 0 ||
strcmp(topic, strcat(mqttTopic1, "/col")) == 0)
{
colorFromDecOrHexString(col, &white, (char*)payload);
colorUpdated(1);
return;
}
if (strcmp(topic, strcat(mqttTopic0, "/api")) == 0 ||
strcmp(topic, strcat(mqttTopic1, "/api")) == 0)
{
handleSet(String((char*)payload));
return;
}
}
void publishStatus()
{
if (!mqtt.connected()) return;
char s[4];
sprintf(s,"%ld", bri);
mqtt.publish(strcat(mqttTopic0, "/g") , s);
XML_response(false);
mqtt.publish(strcat(mqttTopic0, "/vs"), obuf);
}
bool reconnectMQTT()
{
if (mqtt.connect(escapedMac.c_str()))
{
//re-subscribe to required topics
if (mqttTopic0[0] != 0)
{
mqtt.subscribe(mqttTopic0);
mqtt.subscribe(strcat(mqttTopic0, "/col"));
mqtt.subscribe(strcat(mqttTopic0, "/api"));
}
if (mqttTopic1[0] != 0)
{
mqtt.subscribe(mqttTopic1);
mqtt.subscribe(strcat(mqttTopic1, "/col"));
mqtt.subscribe(strcat(mqttTopic1, "/api"));
}
}
return mqtt.connected();
}
bool initMQTT()
{
if (WiFi.status() != WL_CONNECTED) return false;
if (mqttServer[0] == 0) return false;
IPAddress mqttIP;
if (mqttIP.fromString(mqttServer)) //see if server is IP or domain
{
mqtt.setServer(mqttIP,1883);
} else {
mqtt.setServer(mqttServer,1883);
}
mqtt.setCallback(callbackMQTT);
return true;
}
void handleMQTT()
{
if (WiFi.status() != WL_CONNECTED || !mqttInit) return;
if (!mqtt.connected() && millis() - lastMQTTReconnectAttempt > 5000)
{
lastMQTTReconnectAttempt = millis();
if (!reconnectMQTT()) return;
}
mqtt.loop();
}