mqtt code added

This commit is contained in:
2021-05-02 21:07:20 +02:00
parent e174897f22
commit 4f6b71a615
10 changed files with 1445 additions and 186 deletions

1
.gitignore vendored
View File

@@ -3,4 +3,5 @@
.vscode/c_cpp_properties.json .vscode/c_cpp_properties.json
.vscode/launch.json .vscode/launch.json
.vscode/ipch .vscode/ipch
.vscode/settings.json
**/.DS_Store **/.DS_Store

653
lib/pubsubclient/PubSubClient.cpp Executable file
View File

@@ -0,0 +1,653 @@
/*
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,1);
}
boolean PubSubClient::connect(const char *id, const char *user, const char *pass) {
return connect(id,user,pass,0,0,0,0,1);
}
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,1);
}
boolean PubSubClient::connect(const char *id, const char *user, const char *pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage) {
return connect(id,user,pass,willTopic,willQos,willRetain,willMessage,1);
}
boolean PubSubClient::connect(const char *id, const char *user, const char *pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage, boolean cleanSession) {
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 = MQTT_MAX_HEADER_SIZE;
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 = 0x04|(willQos<<3)|(willRetain<<5);
} else {
v = 0x00;
}
if (cleanSession) {
v = 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);
CHECK_STRING_LENGTH(length,id)
length = writeString(id,buffer,length);
if (willTopic) {
CHECK_STRING_LENGTH(length,willTopic)
length = writeString(willTopic,buffer,length);
CHECK_STRING_LENGTH(length,willMessage)
length = writeString(willMessage,buffer,length);
}
if(user != NULL) {
CHECK_STRING_LENGTH(length,user)
length = writeString(user,buffer,length);
if(pass != NULL) {
CHECK_STRING_LENGTH(length,pass)
length = writeString(pass,buffer,length);
}
}
write(MQTTCONNECT,buffer,length-MQTT_MAX_HEADER_SIZE);
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()) {
yield();
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 == 5) {
// 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;
// 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 < MQTT_MAX_HEADER_SIZE + 2+strlen(topic) + plength) {
// Too long
return false;
}
// Leave room in the buffer for header and variable length field
uint16_t length = MQTT_MAX_HEADER_SIZE;
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-MQTT_MAX_HEADER_SIZE);
}
return false;
}
boolean PubSubClient::publish_P(const char* topic, const char* payload, boolean retained) {
return publish_P(topic, (const uint8_t*)payload, strlen(payload), retained);
}
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::beginPublish(const char* topic, unsigned int plength, boolean retained) {
if (connected()) {
// Send the header and variable length field
uint16_t length = MQTT_MAX_HEADER_SIZE;
length = writeString(topic,buffer,length);
//uint16_t i;
uint8_t header = MQTTPUBLISH;
if (retained) {
header |= 1;
}
size_t hlen = buildHeader(header, buffer, plength+length-MQTT_MAX_HEADER_SIZE);
uint16_t rc = _client->write(buffer+(MQTT_MAX_HEADER_SIZE-hlen),length-(MQTT_MAX_HEADER_SIZE-hlen));
lastOutActivity = millis();
return (rc == (length-(MQTT_MAX_HEADER_SIZE-hlen)));
}
return false;
}
int PubSubClient::endPublish() {
return 1;
}
size_t PubSubClient::write(uint8_t data) {
lastOutActivity = millis();
return _client->write(data);
}
size_t PubSubClient::write(const uint8_t *buffer, size_t size) {
lastOutActivity = millis();
return _client->write(buffer,size);
}
size_t PubSubClient::buildHeader(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 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[MQTT_MAX_HEADER_SIZE-llen+i] = lenBuf[i];
}
return llen+1; // Full header size is variable length bit plus the 1-byte fixed header
}
boolean PubSubClient::write(uint8_t header, uint8_t* buf, uint16_t length) {
uint16_t rc;
uint8_t hlen = buildHeader(header, buf, length);
#ifdef MQTT_MAX_TRANSFER_SIZE
uint8_t* writeBuf = buf+(MQTT_MAX_HEADER_SIZE-hlen);
uint16_t bytesRemaining = length+hlen; //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+(MQTT_MAX_HEADER_SIZE-hlen),length+hlen);
lastOutActivity = millis();
return (rc == hlen+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 = MQTT_MAX_HEADER_SIZE;
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-MQTT_MAX_HEADER_SIZE);
}
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 = MQTT_MAX_HEADER_SIZE;
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-MQTT_MAX_HEADER_SIZE);
}
return false;
}
void PubSubClient::disconnect() {
buffer[0] = MQTTDISCONNECT;
buffer[1] = 0;
_client->write(buffer,2);
_state = MQTT_DISCONNECTED;
_client->flush();
_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;
}

173
lib/pubsubclient/PubSubClient.h Executable file
View File

@@ -0,0 +1,173 @@
/*
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)
// Maximum size of fixed header and variable length size header
#define MQTT_MAX_HEADER_SIZE 5
#if defined(ESP8266) || defined(ESP32)
#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
#define CHECK_STRING_LENGTH(l,s) if (l+2+strlen(s) > MQTT_MAX_PACKET_SIZE) {_client->stop();return false;}
class PubSubClient : public Print {
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);
// Build up the header ready to send
// Returns the size of the header
// Note: the header is built at the end of the first MQTT_MAX_HEADER_SIZE bytes, so will start
// (MQTT_MAX_HEADER_SIZE - <returned size>) bytes into the buffer
size_t buildHeader(uint8_t header, uint8_t* buf, uint16_t length);
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);
boolean connect(const char* id, const char* user, const char* pass, const char* willTopic, uint8_t willQos, boolean willRetain, const char* willMessage, boolean cleanSession);
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 char* payload, boolean retained);
boolean publish_P(const char* topic, const uint8_t * payload, unsigned int plength, boolean retained);
// Start to publish a message.
// This API:
// beginPublish(...)
// one or more calls to write(...)
// endPublish()
// Allows for arbitrarily large payloads to be sent without them having to be copied into
// a new buffer and held in memory at one time
// Returns 1 if the message was started successfully, 0 if there was an error
boolean beginPublish(const char* topic, unsigned int plength, boolean retained);
// Finish off this publish message (started with beginPublish)
// Returns 1 if the packet was sent successfully, 0 if there was an error
int endPublish();
// Write a single byte of payload (only to be used with beginPublish/endPublish)
virtual size_t write(uint8_t);
// Write size bytes from buffer into the payload (only to be used with beginPublish/endPublish)
// Returns the number of bytes written
virtual size_t write(const uint8_t *buffer, size_t size);
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

@@ -12,4 +12,9 @@
platform = espressif32 platform = espressif32
board = esp32dev board = esp32dev
framework = arduino framework = arduino
lib_deps = erropix/ESP32 AnalogWrite@^0.2 monitor_speed = 115200
lib_deps =
erropix/ESP32 AnalogWrite@^0.2
Aasim-A/AsyncTimer

278
src/led.cpp Normal file
View File

@@ -0,0 +1,278 @@
#include "led.h"
#include "analogWrite.h"
#include "timer.h"
uint64_t lastmillis = 0;
//_led ledarray[] = {
c_led dimFL(DIM_FL, "dim_FL");
c_led dimFR(DIM_FR, "dim_FR");
c_led dimRL(DIM_RL, "dim_RL");
c_led dimRR(DIM_RR, "dim_RR");
c_led blinkFL(BLINK_FL, "blink_FL");
c_led blinkFR(BLINK_FR, "blink_FR");
c_led interiourLed(INTERIOUR, "interiour");
void c_led::begin(void)
{
Serial.printf("LED %s begin", _ledName.c_str());
pinMode(_pin, OUTPUT);
digitalWrite(_pin, false);
_ledstate = false;
}
void c_led::setState(e_ledstate newstate)
{
if (newstate != noChange)
{
_state = newstate;
_newstate = true;
_timer = 0;
Serial.printf("led %s: setstate %s\n", _ledName.c_str(), ledStateToString(newstate).c_str());
}
if(newstate == led_blink)
{
_ledstate = false;
}
}
void c_led::init()
{
Serial.printf("LED %s: init\n", _ledName.c_str());
if (DIM_STEP == 0 || DIM_TIME < DIM_STEP)
{
_dimstepms = 1;
_dimstep = 10;
}
else
{
_dimstepms = DIM_TIME / DIM_STEP;
_dimstep = DIM_RES / DIM_STEP;
}
_dimmer = 0;
_timer = 0;
_state = led_off;
//_newstate = true;
}
void c_led::update(void)
{
//Serial.printf("led %s update, state = %s, newstate = %s\n", _ledName.c_str(), ledStateToString(_state).c_str(), String(_newstate).c_str());
switch (_state)
{
case led_off:
{
digitalWrite(_pin, false);
_ledstate = false;
}
break;
case led_dim_on:
{
if (_newstate)
{
_dimmer = 0;
_timer = millis();
_newstate = false;
}
uint64_t currentmillis = millis();
if (currentmillis - _timer > _dimstepms)
{
_timer = currentmillis;
analogWrite(_pin, _dimmer, DIM_RES);
_dimmer += _dimstep;
}
if (_dimmer > DIM_RES)
{
setState(led_on);
}
}
break;
case led_on:
{
digitalWrite(_pin, true);
_newstate = false;
_ledstate = true;
}
case led_dim_off:
{
}
break;
case led_blink:
{
uint64_t currentmillis = millis();
if (currentmillis - _timer > BLINKSPEED)
{
//Serial.printf("%s timer expired\n", _ledName.c_str());
_ledstate = !_ledstate;
digitalWrite(_pin, _ledstate);
_timer = currentmillis;
}
}
break;
default:
{
}
break;
}
}
void c_led::toggle(void)
{
switch (_state)
{
case led_on:
setState(led_off);
break;
case led_dim_on:
setState(led_off);
break;
case led_off:
setState(led_on);
break;
case led_dim_off:
setState(led_on);
break;
case led_blink:
setState(noChange);
break;
default:
setState(led_off);
}
}
void initLeds(void)
{
Serial.println("InitLeds");
dimFL.begin(); //
dimFR.begin(); //setState(led_on);
dimRL.begin(); //setState(led_on);
dimRR.begin(); //etState(led_on);
blinkFR.begin(); //setState(led_on);
blinkFL.begin(); //setState(led_on);
interiourLed.begin(); //setState(led_on);
analogWriteResolution(10);
dimFL.setState(led_on);
dimFR.setState(led_on);
dimRL.setState(led_on);
dimRR.setState(led_on);
blinkFR.setState(led_blink);
blinkFL.setState(led_blink);
interiourLed.setState(led_on);
}
void runLeds(void)
{
dimFL.update();
dimFR.update();
dimRL.update();
dimRR.update();
blinkFL.update();
blinkFR.update();
interiourLed.update();
}
void setLeds(e_ledstate dim_FL,
e_ledstate dim_FR,
e_ledstate dim_RL,
e_ledstate dim_RR,
e_ledstate blink_FR,
e_ledstate blink_FL,
e_ledstate interiour)
{
dimFL.setState(dim_FL);
dimFR.setState(dim_FR);
dimRL.setState(dim_RL);
dimRR.setState(dim_RR);
blinkFR.setState(blink_FR);
blinkFL.setState(blink_FL);
interiourLed.setState(interiour);
}
e_ledpattern currentpattern = allOff;
void setLedPattern(e_ledpattern setpattern)
{
Serial.printf("SetLedPattern %i\n", setpattern);
switch (setpattern)
{
case allOff:
{
setLeds(led_off, led_off, led_off, led_off, led_off, led_off, led_off);
}
break;
case allOn:
{
setLeds(led_on, led_on, led_on, led_on, led_on, led_on, led_on);
}
break;
case panic:
{
//setLeds(noChange, noChange, noChange, noChange, led_off, led_off, noChange);
setLeds(noChange, noChange, noChange, noChange, led_blink, led_blink, noChange);
}
break;
case night:
{
setLeds(led_on, led_on, led_on, led_on, noChange, noChange, led_on);
}
break;
case turnLeft:
{
setLeds(noChange, noChange, noChange, noChange, led_off, led_blink, noChange);
}
break;
case turnRight:
{
setLeds(noChange, noChange, noChange, noChange, led_blink, led_off, noChange);
}
break;
case interiourOn:
{
setLeds(noChange, noChange, noChange, noChange, noChange, noChange, led_on);
}
break;
case interiourOff:
{
setLeds(noChange, noChange, noChange, noChange, noChange, noChange, led_off);
}
break;
default:
{
}
break;
}
currentpattern = setpattern;
}
String ledStateToString(e_ledstate state)
{
switch (state)
{
case led_off:
return "led Off";
break;
case led_dim_on:
return "led_dim_on";
break;
case led_on:
return "led On";
break;
case led_dim_off:
return "led_dim_off";
break;
case led_blink:
return "led_blink";
break;
case noChange:
return "noChange";
break;
default:
return "invalid";
break;
}
}

87
src/led.h Normal file
View File

@@ -0,0 +1,87 @@
#pragma once
#include "Arduino.h"
#include "timer.h"
#define DIM_FL 18 //
#define DIM_FR 27 //
#define BLINK_FL 4
#define BLINK_FR 17 //
#define DIM_RL 14
#define DIM_RR 26 //
#define INTERIOUR 5 //
#define NUM_LEDS 7
#define DIM_TIME 1000
#define DIM_RES 1024
#define DIM_STEP 255
#define DIM_STEPMS (DIM_TIME / DIM_STEP)
#define BLINKSPEED 400
typedef enum
{
Dim_FL,
Dim_FR,
Dim_RL,
Dim_RR,
Blink_FL,
Blink_FR,
Interiour
} e_leds;
typedef enum
{
led_off,
led_dim_on,
led_on,
led_dim_off,
led_blink,
noChange
} e_ledstate;
typedef enum
{
allOff,
allOn,
panic,
night,
turnLeft,
turnRight,
interiourOn,
interiourOff
} e_ledpattern;
String ledStateToString(e_ledstate state);
class c_led
{
const uint8_t _pin;
e_ledstate _state;
uint64_t _timer;
uint32_t _dimmer;
bool _newstate;
bool _ledstate;
uint64_t _dimstepms;
uint32_t _dimstep;
String _ledName;
void init();
public:
c_led(uint8_t pin, String name) : _pin(pin)
{
_ledName = name;
init();
}
void begin(void);
void update(void);
void setState(e_ledstate newstate);
void toggle(void);
};
void initLeds(void);
void runLeds(void);
void setLedPattern(e_ledpattern setpattern);

View File

@@ -1,195 +1,19 @@
#include <Arduino.h> #include <Arduino.h>
#include "analogWrite.h" #include "led.h"
#include "mqtt.h"
#define DIM_FL 18 //
#define DIM_FR 27 //
#define BLINK_FL 4
#define BLINK_FR 17 //
#define DIM_RL 14
#define DIM_RR 26 //
#define INTERIOUR 5 //
#define BLINKSPEED 400
#define NUM_LEDS 7
#define DIM_TIME 1000
#define DIM_RES 1024
#define DIM_STEP 255
#define DIM_STEPMS (DIM_TIME / DIM_STEP)
uint64_t lastmillis = 0;
typedef enum
{
Dim_FL,
Dim_FR,
Dim_RL,
Dim_RR,
Blink_FL,
Blink_FR,
Interiour
} e_leds;
typedef enum
{
led_off,
led_dim_on,
led_on,
led_dim_off,
led_blink
} e_ledstate;
class c_led
{
//const e_leds _led;
const uint8_t _pin;
e_ledstate _state;
uint64_t _timer;
uint32_t _dimmer;
bool _newstate;
uint64_t _dimstepms;
uint32_t _dimstep;
public:
c_led(uint8_t pin) : _pin(pin)
{
if (DIM_STEP == 0 || DIM_TIME < DIM_STEP)
{
_dimstepms = 1;
_dimstep = 10;
}
else
{
_dimstepms = DIM_TIME / DIM_STEP;
_dimstep = DIM_RES / DIM_STEP;
}
_dimmer = 0;
_timer = 0;
_state = led_off;
_newstate = true;
}
void begin(void)
{
pinMode(_pin, OUTPUT);
digitalWrite(_pin, false);
}
void update(void)
{
switch (_state)
{
case led_off:
{
digitalWrite(_pin, false);
}
break;
case led_dim_on:
{
if (_newstate)
{
_dimmer = 0;
_timer = millis();
}
uint64_t currentmillis = millis();
if (currentmillis - _timer > _dimstepms)
{
_timer = currentmillis;
analogWrite(_pin, _dimmer, DIM_RES);
_dimmer += _dimstep;
}
if (_dimmer > DIM_RES)
{
setState(led_on);
}
_newstate = false;
}
break;
case led_on:
{
digitalWrite(_pin, true);
_newstate = false;
}
}
}
void setState(e_ledstate newstate)
{
_state = newstate;
_newstate = true;
}
void toggle(void)
{
switch (_state)
{
case led_on:
setState(led_off);
break;
case led_dim_on:
setState(led_off);
break;
case led_off:
setState(led_on);
break;
case led_dim_off:
setState(led_on);
break;
default:
setState(led_off);
}
}
};
c_led ledarray[] = {
c_led(DIM_FL),
c_led(DIM_FR),
c_led(DIM_RL),
c_led(DIM_RR),
c_led(BLINK_FL),
c_led(BLINK_FR),
c_led(INTERIOUR)};
void sceneBlinkLeft(void)
{
}
void setup() void setup()
{ {
// put your setup code here, to run once: Serial.begin(115200);
for (auto led : ledarray) initLeds();
{ initWiFi();
led.begin(); initMQTT();
}
analogWriteResolution(10);
ledarray[Dim_FL].setState(led_on);
ledarray[Dim_FR].setState(led_on);
ledarray[Dim_RL].setState(led_on);
ledarray[Dim_RR].setState(led_on);
ledarray[Interiour].setState(led_on);
} }
void loop() void loop()
{ {
// put your main code here, to run repeatedly: runWifi();
for (auto led : ledarray) runLeds();
{ runMQTT();
led.update();
}
uint64_t currentmillis = millis();
if (currentmillis - lastmillis > BLINKSPEED)
{
ledarray[Blink_FR].toggle();
ledarray[Blink_FL].toggle();
ledarray[Dim_FL].toggle();
ledarray[Dim_FR].toggle();
ledarray[Dim_RL].toggle();
ledarray[Dim_RR].toggle();
lastmillis = currentmillis;
}
} }

168
src/mqtt.cpp Normal file
View File

@@ -0,0 +1,168 @@
#include <SPI.h>
#include "Arduino.h"
#include "WiFi.h"
#include "PubSubClient.h"
#include "timer.h"
#include "led.h"
// Update these with values suitable for your network.
byte mac[] = {0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xED};
IPAddress MQTTserver(192, 168, 2, 5);
const char *SSID = "poes";
const char *PWD = "Rijnstraat214";
c_timer mqttTimer("MQTT");
c_timer WifiTimer("WiFi");
WiFiClient wificlient;
PubSubClient client(wificlient);
void callback(char *topic, byte *payload, unsigned int length)
{
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
String str_payload;
for (int i = 0; i < length; i++)
{
Serial.print((char)payload[i]);
str_payload += (char)payload[i];
}
Serial.println("");
if(!str_payload.compareTo("AllOff"))
{
Serial.println("MQTT payload: AllOff");
setLedPattern(allOff);
}
else if(str_payload == "AllOn")
{
setLedPattern(allOn);
}
else if(str_payload == "Panic")
{
Serial.println("MQTT payload: panic");
setLedPattern(panic);
}
else if(str_payload == "TurnLeft")
{
setLedPattern(turnLeft);
}
else if(str_payload == "TurnRight")
{
setLedPattern(turnRight);
}
else if(str_payload == "Night")
{
setLedPattern(night);
}
else if(str_payload == "InteriourOn")
{
setLedPattern(interiourOn);
}
else if(str_payload == "InteriourOff")
{
setLedPattern(interiourOff);
}
else{
Serial.println("Invalid payload");
return;
}
client.publish("VW-BUS/ledState",(const char*) payload);
Serial.println();
}
void reconnect()
{
// Loop until we're reconnected
if (!client.connected() && mqttTimer.expired())
{
Serial.print("Attempting MQTT connection...");
// Attempt to connect
if (client.connect("VW-BUS-connection"))
{
Serial.println("connected");
// Once connected, publish an announcement...
client.publish("VW-BUS/initState", "online");
client.publish("VW-BUS/ledState","ledOff");
// ... and resubscribe
client.subscribe("VW-BUS/ledState/set");
}
else
{
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
mqttTimer.setInterval(5000);
}
}
}
void initMQTT()
{
client.setServer(MQTTserver, 1883);
client.setCallback(callback);
// Allow the hardware to sort itself out
delay(1500);
}
void runMQTT()
{
if (!client.connected() && mqttTimer.expired())
{
reconnect();
}
client.loop();
mqttTimer.handle();
}
uint8_t initcount = 0;
bool WifiiIsConnected(void)
{
if (WiFi.status() == WL_CONNECTED)
{
return true;
}
return false;
}
void initWiFi()
{
Serial.print("Connectiog to ");
WiFi.begin(SSID, PWD);
Serial.println(SSID);
while (!WifiiIsConnected() && initcount < 20)
{
Serial.print(".");
delay(200);
initcount++;
}
if (WifiiIsConnected())
{
Serial.print("Wifi Connected!.");
Serial.println(WiFi.localIP());
return;
}
Serial.print("wifi connection failed, retrying.\n");
}
void runWifi(void)
{
if(!WifiiIsConnected() && WifiTimer.expired())
{
initWiFi();
WifiTimer.setInterval(5000);
return;
}
WifiTimer.handle();
}

7
src/mqtt.h Normal file
View File

@@ -0,0 +1,7 @@
#pragma once
void initMQTT();
void runMQTT();
void initWiFi();
void runWifi(void);

63
src/timer.h Normal file
View File

@@ -0,0 +1,63 @@
#pragma once
#include <AsyncTimer.h>
class c_timer
{
AsyncTimer _timer;
bool _timerDone;
uint64_t _timerInterval;
String _timerName;
short _timerID;
public:
c_timer(String timerName)
{
_timerDone = true;
_timerName = timerName;
}
// c_timer()
// {
// _timerDone = true;
// _timerName = "";
// }
void setTimerName(String timerName)
{
_timerName = timerName;
}
short setInterval(uint64_t intervalms)
{
if (!_timerDone)
{
Serial.printf("%s(%hu) not ready\n", _timerName.c_str(), _timerID);
return _timerID;
}
_timerDone = false;
_timerInterval = intervalms;
_timerID = _timer.setTimeout([&]() {
_timerDone = true;
Serial.printf("%s(%hu) timer done\n", _timerName.c_str(), _timerID);
},
_timerInterval);
Serial.printf("%s (%hu) timer started ( %llu ms)\n", _timerName.c_str(), _timerID, intervalms);
return _timerID;
}
bool expired(void)
{
return _timerDone;
}
bool handle(void)
{
_timer.handle();
return _timerDone;
}
void cancel(short ID)
{
_timer.cancel(ID);
}
};