text: /*
   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 3600
  #endif
  
  // MQTT_SOCKET_TIMEOUT: socket timeout interval in Seconds
  #ifndef MQTT_SOCKET_TIMEOUT
  #define MQTT_SOCKET_TIMEOUT 60
  #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
  