An Open-Source platform to create digital devices and interactive objects that sense and control physical devices. | Arduino Tutorials | |
Arduino Projects |
In my previous MKR1010 post I shown how to enable the BLE support for the board by upgrading the firmware.
MKR WiFi 1010 - Enable BLE Support
In this post, I will display communicating with the MKR1010 remotely using MQTT to control the relays in the MKR Relay Shield. The MKR1010 uses a ESP32 WiFi module by U-BLOX which is an improvement from the MKR1000. The WiFi module is quite stable and configured with my router without issue after being programed. I'm using the Mosquitto MQTT Broker running on a Raspberry Pi to publish and subscribe to the topics being hosted by the MKR1010. These topics cover the Temp and Humidity from the HUMI-01 as well as the direction of DC Motor using the Relays on the MKR Relay Shield as an H-Bridge. The DC motor will be used for a conveyor belt that will be used in conjunction with the Robot Arm I am working on.
MKR1010 and Relay Board Config:
Hardware used:
MKR1010
MKR Relay Shield
OSEPP HUMI-01 Temp and Humidity Sensor
Makeblock 6v Geared DC Motor
1 - 3.7 LiPi Battery
1 - 5V Li-ion Battery
Software used:
Arduino IDE 1.8.8 Hourly Build
WiFiNINA version 1.3.0 for WiFi communication
Arduinojson by Beniot Blanchon - version 5.13.3
ArduinoMqtt by Oleg Kovalenko version 1.5.1
MQTT by Joel Gaehwiller version 2.4.1
DHT by Rob Tillaart for HUMI-01 reading
http://arduino.cc/playground/Main/DHTLib
Set-up
To run this example, I started with the Examples->WiFiNINA->WiFiWebClient to get the remote connection to the router set. Once the communication was proven out, the ArduinoMqtt, Arduinojson, and MQTT Libraries were added to the Arduino IDE via Sketch-Include Library->Manage Libraries menu option to get to the Library Manger window.
From the Library Manger window, install ArduinoMqtt, Arduinojson (version 5.13.3), and MQTT. Once these are installed, they can be included in the Arduino IDE Project.
#include <WiFiNINA.h> #include <MQTT.h> #include <ArduinoJson.h>
Instances of WiFiClient and a MQTTClient are needed to communicated remotely.
WiFiClient net; MQTTClient client;
A Secrets header file was added to create the WiFi and MQTT constants.
const char WIFI_SSID[] = "MYSSID"; // WiFI ssid const char WIFI_PASS[] = "12345"; //WiFI password const char mqttServer[] = "192.168.10.130"; // broker, with shiftr.io it's "broker.shiftr.io" const int mqttServerPort = 1883; // broker mqtt port const char key[] = " "; // broker key const char secret[] = " "; // broker secret const char device[] = " "; // broker device identifie
I create set of interfaces to cover the Relay Board Analog and Relay configurations using C++ Templates. This is still a work in progress but this is what the main interface looks like.
/* MKRRelayBoard.h */ #pragma once #ifndef MKRRELAYBOARD_H_ #define MKRRELAYBOARD_H_ #include "MKRRelay.hpp" #include "MKRAnalogPort.hpp" /* MKR WiFi 1010 Analog Pins are numbered A1 = 16 A2 = 17 A3 = 18 A4 = 19 */ enum class AnalogPinVal { A1Pin = 16, A2Pin = 17, A3Pin = 18, A4Pin = 19 }; static const AnalogPinVal analog_pins[] = { AnalogPinVal::A1Pin, AnalogPinVal::A2Pin, AnalogPinVal::A3Pin, AnalogPinVal::A4Pin, }; enum class I2CPinVal { SCLPin = 12, SDAPin = 11 }; enum class RelayPinVal { Relay1Pin = 1, Relay2Pin = 2, }; template<class T> class MKRRelayBoard : public MKRRelay<T> , public MKRAnalogPort<T> { public: MKRRelayBoard(); MKRRelayBoard(T rCmd); ~MKRRelayBoard(); void Begin(); void setCmdVal(T cVal); T getRBRelayNum(T rVal); void initAllRelays(void); void initSingleRelay(T rVal); void setRBRelayOn(T rVal); void setRBRelayOff(T rVal); T getRBRelayState(T rVal); T getRBAnalogPinNum(T aPin); T readRBAnalogPin(T aPin); void writeRBAnalogPin(AnalogPinVal aPin, int outVal); private: //T relayCmd; MKRRelay<int>* mkr_relay1; MKRRelay<int>* mkr_relay2; MKRAnalogPort<int>* analog_pin1; MKRAnalogPort<int>* analog_pin2; MKRAnalogPort<int>* analog_pin3; MKRAnalogPort<int>* analog_pin4; I2CPinVal rbSDA = I2CPinVal::SDAPin; I2CPinVal rbSCL = I2CPinVal::SCLPin; }; #endif /* MKRRELAYBOARD_H_ */
From the Arduino IDE project, an instance of the Relay Board is created as such:
MKRRelayBoard<int>* mkrRelayBoard = new MKRRelayBoard<int>{CMD1};
A connection to the WiFi router needs to be established to initiate the communication with the MQTT broker.
unsigned long lastMillis = 0; void connect() { Serial.print("checking wifi..."); while ( status != WL_CONNECTED) { status = WiFi.begin(WIFI_SSID, WIFI_PASS); Serial.print("."); delay(1000); } Serial.println("\nconnected to WiFi!\n"); client.begin(mqttServer, mqttServerPort, net); Serial.println("connecting to broker..."); while (!client.connect(device, key, secret)) { Serial.print("."); delay(1000); } Serial.println("Connected to MQTT"); client.onMessage(messageReceived); client.subscribe("/hello"); client.subscribe("/get_temp"); client.subscribe("/get_humid"); }
When a message is recieved, the message is passed to the messageReceived method
client.onMessage(messageReceived);
The messageReceived method parses the message using Json and assigns the appropriate values to the topic variables.
void messageReceived(String &topic, String &payload) { String ledState = "Blink LED STATE "; String curState = " "; String tempSet = "CurrentTemp = "; String currentTemp = " "; String humidSet = "CurrentHumid = "; String currentHumid = " "; int aPin2; aPin2 = mkrRelayBoard->getRBAnalogPinNum(sensorPin2); Serial.println("incoming: " + topic + " - " + payload); if(topic.equals("/hello")) { StaticJsonBuffer<200> jsonBuffer; JsonObject& root = jsonBuffer.parseObject(payload); String cmd1Val = root["cmd1"]; String cmd2Val = root["cmd2"]; Serial.println("cmd1 = " + cmd1Val); curState = ledState + static_cast<int>(rledState); Serial.println(curState); if(cmd1Val.equals("on")) { mkrRelayBoard->setRBRelayOn(relay_num1); rledState = LedStates::LED_ON; } else if(cmd1Val.equals("off")) { mkrRelayBoard->setRBRelayOff(relay_num1); rledState = LedStates::LED_OFF; } //delay(1000); curState = ledState + LedState; Serial.println(curState ); if(cmd2Val.equals("on")) { mkrRelayBoard->setRBRelayOn(relay_num2); rledState = LedStates::LED_ON; } else if(cmd2Val.equals("off")) { mkrRelayBoard->setRBRelayOff(relay_num2); rledState = LedStates::LED_OFF; } delay(1000); } if(topic.equals("/get_temp")) { DHT.read11(aPin2); currentTemp = tempSet + (DHT.temperature * 9.0/5.0 + 32); client.publish("/temp", currentTemp); } // end of if for "/hello" if(topic.equals("/get_humid")) { DHT.read11(aPin2); currentHumid = humidSet + DHT.humidity; client.publish("/humid", currentHumid); } // end of if for "/hello" }
If a message is received the message is parsed to determine which topic the command is for and then, in the case of 'get_temp' and 'get_humid' will read the sensor and publish the associated values to the appropriate topic. For the relay control (or LED values), the states are set to either on or off. This is performed by calling either the setRBRelayOn or setRBRelayOff.
if(cmd1Val.equals("on")) { mkrRelayBoard->setRBRelayOn(relay_num1); rledState = LedStates::LED_ON; } else if(cmd1Val.equals("off")) { mkrRelayBoard->setRBRelayOff(relay_num1); rledState = LedStates::LED_OFF }
The setup routine just initializes the Serial port for debug display and calls connect.
void setup() { Serial.begin(115200); connect(); }
The main loop, continues to call 'connect' if there is no active connection.
void loop() { client.loop(); // delay(1000); // helps eventually if (!net.connected()) { connect(); } if (millis() - lastMillis > 1000) { lastMillis = millis(); //client.publish("/hello", "world"); //lastMillis = millis(); } }
Once the code is loaded on the MKR1010 and the board is restarted, if the connection to the router is successful, the MQTT broker, Mosquitto running on a Raspberry Pi in this instance, it indicate the board has established a connection.
$ mosquitto 1549360172: mosquitto version 1.4.14 (build date Mon, 10 Jul 2017 23:48:43 +0100) starting 1549360172: Using default config. 1549360172: Opening ipv4 listen socket on port 1883. 1549360172: Opening ipv6 listen socket on port 1883. 1549360183: New connection from 192.168.2.215 on port 1883. 1549360183: New client connected from 192.168.2.215 as (c1, k10, u' ').
From the Raspberry Pi, a topic from the MKR1010 can be subscribed to and a publish command can be sent to get a reading from either the 'temp' topic or the 'humid' topic.
Subscribe to the 'temp' topic:
$ mosquitto_sub -h 192.168.2.130 -p 1883 -t '/temp'
Publish a message to the 'temp' topic
$ mosquitto_pub -h 192.168.2.130 -p 1883 -t '/get_temp' -m ""
Result of sending a publish command to the 'temp' topic
$ mosquitto_sub -h 192.168.2.130 -p 1883 -t '/temp' CurrentTemp = 62.60
To control the Relays from the Relay board, both relays can be controlled in one Publish command.
$ mosquitto_pub -h 192.168.2.130 -p 1883 -t '/hello' -m "{"cmd1" : "on" , "cmd2" : "on"}"
To control the direction of the motor, one command (relay setting) has to be off, while the other is 'on'.
$ mosquitto_pub -h 192.168.2.130 -p 1883 -t '/hello' -m "{"cmd1" : "off" , "cmd2" : "on"}"
If both commands are the same value, the motor stops.
When this is run, the MKR1010 processes the MQTT commands quite quickly with very little latency. This would work nicely for applications needing a low power remote solution.
MKR1010 and MKR Relay Shield in action.
Top Comments