├── 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 | ![Connection diagram](electrical_connections/connect_to_arduino.png?raw=true) 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) --------------------------------------------------------------------------------