Subversion Repositories ESP8266_P1_Meter

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 raymond 1
#ifndef __MQTT_REMOTE_H__
2
#define __MQTT_REMOTE_H__
3
 
4
#include "IMQTTRemote.h"
5
#include <MQTT.h>
6
#include <functional>
7
#include <map>
8
#include <string>
9
#ifdef ESP32
10
#include <WiFi.h>
11
#elif ESP8266
12
#include <ESP8266WiFi.h>
13
#elif defined(ARDUINO_SAMD_MKRWIFI1010)
14
#include <WiFi101.h>
15
#else
16
#error "Unsupported hardware. Sorry!"
17
#endif
18
 
19
/**
20
 * @brief MQTT wrapper for setting up MQTT connection (and will) and provide API for sending and subscribing to
21
 * messages.
22
 */
23
class MQTTRemote : public IMQTTRemote {
24
public:
25
  /**
26
   * Additional configuration where most user can go with defaults.
27
   */
28
  struct Configuration {
29
    /**
30
     * Maximum message size, in bytes, for incoming and outgoing messages. Messages larger than this will be truncated.
31
     * This will be allocated on the heap upon MQTTRemote object creation.
32
     */
33
    uint32_t buffer_size = 1024;
34
 
35
    /**
36
     * MQTT keep alive interval, in seconds. If the client fails to communicate with the broker within the specified
37
     * Keep Alive period, the LWT/Last Will message is sent (by the broker).
38
     */
39
    uint32_t keep_alive_s = 10;
40
 
41
    /**
42
     * if true, will print on Serial on message received. Publish verbosity is controlled by the
43
     * which publish method that is used. Connection information on setup will always be printed out.
44
     */
45
    bool receive_verbose = false;
46
  };
47
 
48
  /**
49
   * @brief Construct a new MQTTRemote object
50
   *
51
   * @param client_id Base ID for this device. This is used for the last will / status
52
   * topic. Example, if this is "esp_now_router", then the status/last will topic will be "esp_now_router/status". This
53
   * is also used as client ID for the MQTT connection. This has to be [a-zA-Z0-9_] only and unique among all MQTT
54
   * clients on the server. It should also be stable across connections.
55
   * @param host MQTT hostname or IP for MQTT server.
56
   * @param port MQTT port number.
57
   * @param username MQTT username.
58
   * @param password MQTT password.
59
   */
60
  MQTTRemote(std::string client_id, std::string host, int port, std::string username, std::string password)
61
      : MQTTRemote(std::move(client_id), std::move(host), port, std::move(username), std::move(password),
62
                   Configuration{}) {}
63
 
64
  /**
65
   * @brief Construct a new MQTTRemote object
66
   *
67
   * @param client_id Base ID for this device. This is used for the last will / status
68
   * topic. Example, if this is "esp_now_router", then the status/last will topic will be "esp_now_router/status". This
69
   * is also used as client ID for the MQTT connection. This has to be [a-zA-Z0-9_] only and unique among all MQTT
70
   * clients on the server. It should also be stable across connections.
71
   * @param host MQTT hostname or IP for MQTT server.
72
   * @param port MQTT port number.
73
   * @param username MQTT username.
74
   * @param password MQTT password.
75
   * @param configuration Additional configuration where most user can go with defaults.
76
   */
77
  MQTTRemote(std::string client_id, std::string host, int port, std::string username, std::string password,
78
             Configuration configuration);
79
 
80
  /**
81
   * Call from Arduino loop() function in main.
82
   */
83
  void handle();
84
 
85
  /**
86
   * @brief Set optional callback on connect state change. Will be called when the client is connected
87
   * to server (every time, so expect calls on reconnection), and on disconnect. The parameter will be true on new
88
   * connection and false on disconnection. Set to {} to clear callback.
89
   */
90
  void setOnConnectionChange(std::function<void(bool connected)> callback = {}) { _on_connection_change = callback; };
91
 
92
  /**
93
   * @brief Publish a message.
94
   *
95
   * @param topic the topic to publish to.
96
   * @param message The message to send. This cannot be larger than the value set for max_message_size in the
97
   * constructor.
98
   * @param retain True to set this message as retained.
99
   * @param qos quality of service for published message (0 (default), 1 or 2)
100
   * @returns true on success, or false on failure.
101
   */
102
  bool publishMessage(std::string topic, std::string message, bool retain = false, uint8_t qos = 0) override;
103
 
104
  /**
105
   * Same as publishMessage(), but will print the message and topic and the result on serial.
106
   */
107
  bool publishMessageVerbose(std::string topic, std::string message, bool retain = false, uint8_t qos = 0) override;
108
 
109
  /**
110
   * @brief returns if there is a connection to the MQTT server.
111
   */
112
  bool connected() override { return _mqtt_client.connected(); }
113
 
114
  /**
115
   * @brief Subscribe to a topic. The callback will be invoked on every new message.
116
   * There can only be one callback per topic. If trying to subscribe to an already subscribe topic, it will be ignored.
117
   * Don't do heavy operations in the callback or delays as this will block the MQTT callback.
118
   *
119
   * Can be called before being connected. All subscriptions will be (re-)subscribed to once a connection is
120
   * (re-)established.
121
   *
122
   * @param message_callback a message callback with the topic and the message. The topic is repeated for convinience,
123
   * but it will always be for the subscribed topic.
124
   * @return true if an subcription was successul. Will return false if there is no active MQTT connection. In this
125
   * case, the subscription will be performed once connected. Will retun false if this subscription is already
126
   * subscribed to.
127
   */
128
  bool subscribe(std::string topic, IMQTTRemote::SubscriptionCallback message_callback) override;
129
 
130
  /**
131
   * @brief Unsubscribe a topic.
132
   */
133
  bool unsubscribe(std::string topic) override;
134
 
135
  /**
136
   * @brief The client ID for this device. This is used for the last will / status
137
   * topic.Example, if this is "esp_now_router", then the status/last will topic will be "esp_now_router/status". This
138
   * has to be [a-zA-Z0-9_] only.
139
   */
140
  std::string &clientId() override { return _client_id; }
141
 
142
private:
143
  void onMessage(MQTTClient *client, char topic_cstr[], char message_cstr[], int message_size);
144
  void setupWill();
145
 
146
private:
147
  std::string _client_id;
148
  std::string _host;
149
  std::string _username;
150
  std::string _password;
151
  bool _receive_verbose;
152
  WiFiClient _wifi_client;
153
  MQTTClient _mqtt_client;
154
  bool _was_connected = false;
155
  std::function<void(bool)> _on_connection_change;
156
  std::map<std::string, SubscriptionCallback> _subscriptions;
157
  unsigned long _last_connection_attempt_timestamp_ms = 0;
158
};
159
 
160
#endif // __MQTT_REMOTE_H__