├── LICENSE
├── README.md
├── electrical_connections
├── connect_to_arduino.png
├── esp8266_adapter_pcb.jpg
├── esp8266_adapter_pcb_bottom.png
├── esp8266_adapter_pcb_pinout.png
└── esp8266_adapter_pcb_top.png
├── init.lua
├── mqttduino.ino
└── mqttduino.lua
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Suxsem
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # **MQTTDUINO**
2 |
3 | ###An MQTT client for Arduinos connected to an esp8266 board
4 |
5 |
6 | # **FEATURES**
7 | - Subscribe to topics
8 | - Send messages
9 | - Receive messages
10 | - All qos levels
11 | - Messages retain
12 | - Authentication with username and password
13 | - Last will and testament (in topic [mqtt id]/status)
14 | - Auto reconnect on wifi drop or mqtt broker drop!
15 | - Auto reset esp8266 on lock up!
16 | - VERY easy to use and reliable, low memory footprint
17 | - (TODO) SSL connection (can't do it for now due to memory constraint of nodemcu firmware)
18 |
19 | # **USAGE**
20 |
21 | ### 1) Connect esp8266 to Arduino
22 | DISCLAIMER! I have NOT much experience in electronics, this is MY connection diagram and it's working well for me, but I don't know if it's 100% correct
23 |
24 | 
25 |
26 | ### 2) Install nodemcu lua firmware on esp8266
27 | I'm using 20150213 version, you can use any version from 20150212, hoping that future releases will not break compatibility with the script
28 | You can find it there: https://github.com/nodemcu/nodemcu-firmware
29 |
30 |
31 | ### 3) Push mqttduino script on esp8266
32 | Copy mqttduino.lua and init.lua on the esp8266
33 | You can do it with LuaLoader: http://benlo.com/esp8266/
34 | Don't forget to reboot the esp8266 after copying files
35 |
36 |
37 | ### 4) The Arduino sketch
38 | The mqttduino.ino is a template for your sketch.
39 | The template is self-explanatory
40 |
41 | # WARNING!
42 | - I suggest to increate the Arduino serial buffer size in
43 | ```C:\Program Files (x86)\Arduino\hardware\arduino\avr\cores\arduino\HardwareSerial.h```
44 | adding
45 | ```
46 | #define SERIAL_TX_BUFFER_SIZE 100
47 | #define SERIAL_RX_BUFFER_SIZE 100
48 | ```
49 | under
50 | ```
51 | ...
52 | #define SERIAL_TX_BUFFER_SIZE 64
53 | #define SERIAL_RX_BUFFER_SIZE 64
54 | #endif
55 | #endif
56 | ```
57 |
58 | - The script CAN'T receive messages or topics that contains the | character because it's used internally as a separator. Please don't use this character in topics or messages.
59 | - When the Arduino is subscribing to a topic or publishing a message, only one message will be queued. (Due to memory constraint)
--------------------------------------------------------------------------------
/electrical_connections/connect_to_arduino.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suxsem/Mqttduino/450d1ff90fb360a9d291f5023ecff162569dcd21/electrical_connections/connect_to_arduino.png
--------------------------------------------------------------------------------
/electrical_connections/esp8266_adapter_pcb.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suxsem/Mqttduino/450d1ff90fb360a9d291f5023ecff162569dcd21/electrical_connections/esp8266_adapter_pcb.jpg
--------------------------------------------------------------------------------
/electrical_connections/esp8266_adapter_pcb_bottom.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suxsem/Mqttduino/450d1ff90fb360a9d291f5023ecff162569dcd21/electrical_connections/esp8266_adapter_pcb_bottom.png
--------------------------------------------------------------------------------
/electrical_connections/esp8266_adapter_pcb_pinout.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suxsem/Mqttduino/450d1ff90fb360a9d291f5023ecff162569dcd21/electrical_connections/esp8266_adapter_pcb_pinout.png
--------------------------------------------------------------------------------
/electrical_connections/esp8266_adapter_pcb_top.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Suxsem/Mqttduino/450d1ff90fb360a9d291f5023ecff162569dcd21/electrical_connections/esp8266_adapter_pcb_top.png
--------------------------------------------------------------------------------
/init.lua:
--------------------------------------------------------------------------------
1 | node.compile("mqttduino.lua")
2 | file.remove("mqttduino.lua")
3 | dofile("mqttduino.lc")
--------------------------------------------------------------------------------
/mqttduino.ino:
--------------------------------------------------------------------------------
1 | #define APssid "HomeWIFI" //wifi network ssid
2 | #define APpsw "wifipassword" //wifi netwrok password
3 | #define MQTTid "MqttTestClient" //id of this mqtt client
4 | #define MQTTip "mqtt.myserver.com" //ip address or hostname of the mqtt broker
5 | #define MQTTport 1883 //port of the mqtt broker
6 | #define MQTTuser "client1" //username of this mqtt client
7 | #define MQTTpsw "password1" //password of this mqtt client
8 | #define MQTTalive 120 //mqtt keep alive interval (seconds)
9 | #define MQTTretry 10 //time to wait before reconnect if connection drops (seconds)
10 | #define MQTTqos 2 //quality of service for subscriptions and publishes
11 | #define esp8266reset A5 //arduino pin connected to esp8266 reset pin (analog pin suggested due to higher impedance)
12 | #define esp8266alive 40 //esp8266 keep alive interval (reset board if fail) (seconds)
13 | #define esp8266serial Serial //Serial port to use to communicate to the esp8266 (Serial, Serial1, Serial2, etc)
14 | boolean connected = false;
15 |
16 | void onConnected() { //on connected callback
17 | mqttSubscribe("hello"); //subscribe to "hello" topic
18 | }
19 |
20 | void onDisconnected() { //on disconnected callback
21 | }
22 |
23 | void onMessage(String topic, String message) { //new message callback
24 | }
25 |
26 | // #### DO NOT TOUCH THIS CODE! ####
27 | #define buffer_l 50
28 | #define replyTimeout 5000
29 | char in_buffer[buffer_l + 1];
30 | char cb[1];
31 | boolean success;
32 | boolean messageQueued = false;
33 | unsigned long lastAliveCheck = 0;
34 | void checkComm() {
35 | if (millis() - lastAliveCheck > esp8266alive * 2000UL || lastAliveCheck == 0) {
36 | pinMode(esp8266reset, OUTPUT);
37 | delay(50);
38 | pinMode(esp8266reset, INPUT);
39 | lastAliveCheck = millis();
40 | connected = false;
41 | }
42 | if (esp8266serial.find("[(")) {
43 | esp8266serial.readBytes(cb, 1);
44 | if (cb[0] == 'r') {
45 | //ready
46 | if (connected) {
47 | connected = false;
48 | onDisconnected();
49 | }
50 | lastAliveCheck = millis();
51 | esp8266serial.println("startAlive(" + String(esp8266alive) + ")");
52 | esp8266serial.flush();
53 | esp8266serial.println("connectAP(\"" + String(APssid) + "\", \"" + String(APpsw) + "\")");
54 | esp8266serial.flush();
55 | } else if (cb[0] == 'a') {
56 | lastAliveCheck = millis();
57 | checkComm();
58 | } else if (cb[0] == 'w') {
59 | //wifi connected
60 | esp8266serial.println("mqttInit(\"" + String(MQTTid) + "\", \"" + String(MQTTip) + "\", " + MQTTport + ", \"" + String(MQTTuser)
61 | + "\", \"" + String(MQTTpsw) + "\", " + MQTTalive + ", " + MQTTretry + ")");
62 | esp8266serial.flush();
63 | } else if (cb[0] == 'c') {
64 | //mqtt connected
65 | connected = true;
66 | onConnected();
67 | } else if (cb[0] == 'd') {
68 | //disconnected
69 | connected = false;
70 | onDisconnected();
71 | } else if (cb[0] == 'm') {
72 | //new message
73 | if (messageQueued)
74 | return;
75 | if (!success)
76 | messageQueued = true;
77 | memset(in_buffer, 0, sizeof(in_buffer));
78 | esp8266serial.readBytesUntil('|', in_buffer, buffer_l);
79 | String topic = String(in_buffer);
80 | memset(in_buffer, 0, sizeof(in_buffer));
81 | esp8266serial.readBytesUntil('|', in_buffer, buffer_l);
82 | String message = String(in_buffer);
83 | waitForSuccess();
84 | onMessage(topic, message);
85 | messageQueued = false;
86 | } else if (cb[0] == 'p' || cb[0] == 's') {
87 | success = true;
88 | }
89 | }
90 | }
91 | void waitForSuccess() {
92 | unsigned long started = millis();
93 | while (!success) {
94 | if (!connected || millis() - started > replyTimeout) {
95 | success = true;
96 | break;
97 | }
98 | checkComm();
99 | }
100 | }
101 | void mqttPublish(String topic, String message, byte retain) {
102 | if (!connected)
103 | return;
104 | success = false;
105 | esp8266serial.println("mqttPublish(\"" + topic + "\", \"" + message + "\", " + MQTTqos + ", " + retain + ")");
106 | esp8266serial.flush();
107 | waitForSuccess();
108 | }
109 | void mqttSubscribe(String topic) {
110 | if (!connected)
111 | return;
112 | success = false;
113 | esp8266serial.println("mqttSubscribe(\"" + String(topic) + "\", " + MQTTqos + ")");
114 | esp8266serial.flush();
115 | waitForSuccess();
116 | }
117 | // #### END OF UNTOUCHABLE CODE ####
118 |
119 | void setup() {
120 | esp8266serial.begin(9600); //
121 | esp8266serial.setTimeout(500) //start serial
122 |
123 | while(!connected) //
124 | checkComm(); //wait for first connection
125 | }
126 |
127 | void loop() {
128 | do //
129 | checkComm(); //
130 | while(!connected); //check for incoming messages
131 |
132 | delay(10000);
133 |
134 | mqttPublish("uptime", String(millis()), 0); //publish new message to "uptime" topic, with no retain
135 | mqttPublish("sensor", String(analogRead(A0)), 1); //publish new message to "sensor" topic, with retain
136 | }
137 |
--------------------------------------------------------------------------------
/mqttduino.lua:
--------------------------------------------------------------------------------
1 | _PROMPT = ""
2 | _PROMPT2 = ""
3 |
4 | mqttStatus = false
5 | mqttIp = "0.0.0.0"
6 | mqttPort = 0
7 | mqttRetry = 0
8 | mqttId = ""
9 |
10 | local srv = net.createServer(net.TCP)
11 | srv:listen(80, function(conn)
12 | conn:on("receive",function(conn,payload)
13 | conn:send("MQTTDUINO - Node ID: " .. node.chipid() ..
14 | " - Node MAC: " .. wifi.sta.getmac() ..
15 | " - MQTT status: " .. (mqttStatus == true and mqttId or 'not connected') ..
16 | " - Online since: " .. tmr.time() .. "s")
17 | end)
18 | conn:on("sent",function(conn) conn:close() end)
19 | end)
20 |
21 | mqttInit = function (id, ip, port, user, password, alive, retry)
22 | mqttId = id;
23 | mqttIp = ip
24 | mqttPort = port
25 | mqttRetry = retry * 1000
26 |
27 | m = mqtt.Client(mqttId, alive, user, password)
28 | m:lwt(mqttId .. "/status", "0", 2, 1)
29 |
30 | m:on("offline", function(conn)
31 | if mqttStatus then
32 | print("[(d")
33 | end
34 | mqttStatus = false
35 | tmr.alarm(0, mqttRetry, 1, function()
36 | if mqttStatus then
37 | tmr.stop(0)
38 | else
39 | mqttConnect()
40 | end
41 | end)
42 | end)
43 | m:on("message", function(conn, topic, data)
44 | if data ~= nil then
45 | print("[(m" .. topic .. "|" .. data .. "|")
46 | end
47 | end)
48 |
49 | mqttConnect()
50 | end
51 |
52 | mqttConnect = function ()
53 | m:connect(mqttIp, mqttPort, 0, function(conn)
54 | m:publish(mqttId .. "/status", "1", 2, 1, function(conn)
55 | print("[(c")
56 | mqttStatus = true
57 | end)
58 | end)
59 | end
60 |
61 | mqttSubscribe = function (topic, qos)
62 | m:subscribe(topic, qos, function(conn) print("[(s") end)
63 | end
64 |
65 | mqttPublish = function (topic, message, qos, ret)
66 | m:publish(topic, message, qos, ret, function(conn) print("[(p") end)
67 | end
68 |
69 | connectAP = function (ssid, password)
70 | wifi.setmode(wifi.STATION)
71 | wifi.sta.config(ssid, password)
72 | tmr.alarm(0, 1000, 1, function()
73 | if wifi.sta.getip() ~= nil then
74 | tmr.stop(0)
75 | print("[(w");
76 | end
77 | end)
78 | end
79 |
80 | startAlive = function (interval)
81 | tmr.alarm(1, interval * 1000, 1, function()
82 | print("[(a")
83 | end)
84 | end
85 |
86 | tmr.alarm(0, 10000, 1, function()
87 | tmr.stop(0)
88 | print("[(r")
89 | end)
--------------------------------------------------------------------------------