It's a project that is still growing, but I hope it helps users along the way.
The advantage of the sketch below is that you only need Mosquitto as a broker and that NodeRED does not have to be installed.
The project uses the ArduinoJson library. On the ArduinoJson site you can find more information about the library and how to use it.
Code: Select all
/**
* Arduino MEGA 2560 with Ethernet shield
* MQTT MEGA I/O for Domoticz (JSON)
* Created by M.J. Christ
*/
#include <SPI.h>
#include <Ethernet.h>
#include <ArduinoMqttClient.h>
#include <ArduinoJson.h>
#include <Bounce2.h>
#include "arduino_secrets.h" // Header file containing settings for sketch
// Network settings
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED}; // This must be unique
EthernetClient ethernetClient;
MqttClient mqttClient(ethernetClient);
char broker_user[] = BROKER_USER;
char broker_pass[] = BROKER_PASS;
// MQTT settings
const char broker[] = "192.168.10.30";
int port = 1883;
const char inTopic[] = "domoticz/in"; // Default incoming topic in Domoticz is domoticz/in
const char outTopic[] = "domoticz/out"; // Default outgoing topic in Domoticz is domoticz/in
char myOutput[512];
// Interval settings
unsigned long previousMillis = 0; // Store last time
const long interval = 60000; // interval (milliseconds)
// Input settings
#define numberInputs 2
const int idx_inputArray[numberInputs] = {18, 19};
const int inputArray[8] = {22, 23, 24, 25, 26, 27, 28, 29}; // GPIO input pins
const int invertArray[8] = {0, 1, 0, 0, 0, 0, 0, 0 }; // Invert input pins
#define inputOn 0 // GPIO value input on
#define inputOff 1 // GPIO value input off
// Debouncer settings
Bounce debouncer[numberInputs];
bool lastCycle[numberInputs]; // = {false};
unsigned long debounceDelay = 50; // Debounce time (milliseconds)
// Output settings
#define numberOutputs 4
const char switchType[] = "On/Off";
const int idx_outputArray[numberOutputs] = {18, 19, 20, 21};
const int outputArray[8] = {30, 31, 32, 33, 34, 35, 36, 37}; // GPIO output pins
#define outputOn 0 // GPIO value output on
#define outputOff 1 // GPIO value output off
void setup() {
// Initialize serial for debug
Serial.begin(9600);
// Set input pins
for (int pin = 0; pin < numberInputs; pin++) {
pinMode(inputArray[pin], INPUT_PULLUP);
debouncer[pin] = Bounce();
debouncer[pin].attach(inputArray[pin]);
debouncer[pin].interval(debounceDelay);
lastCycle[pin] = debouncer[pin].read() ? inputOn : inputOff;
}
// Set output pins
for (int pin = 0; pin < numberOutputs; pin++) {
pinMode(outputArray[pin], OUTPUT);
digitalWrite(outputArray[pin], outputOff);
}
// Set MQTT client
mqttClient.setUsernamePassword(broker_user, broker_pass);
mqttClient.onMessage(onMqttMessage);
mqttClient.subscribe(outTopic);
}
void loop(){
// If not connected to the broker, try to connect
while (!mqttClient.connected()) {
startBroker();
}
// Interval request all output states
unsigned long currentMillis = millis();
bool requestStates = false;
DynamicJsonDocument doc(256);
if (currentMillis - previousMillis >= interval) {
// Save the last time
previousMillis = currentMillis;
requestStates = true;
Serial.println("Request all states");
for (int pin = 0; pin < numberOutputs; pin++) {
// Serialize the message
doc.clear();
doc["command"] = "getdeviceinfo";
doc["idx"] = idx_outputArray[pin];
// Send the message
mqttClient.beginMessage(inTopic);
serializeJson(doc, mqttClient);
mqttClient.endMessage();
// show serialization message
serializeJsonPretty(doc, myOutput);
Serial.println(myOutput);
}
}
// (Interval) request all input states
bool thisCycle[numberInputs];
for (int pin = 0; pin < numberInputs; pin++) {
debouncer[pin].update() ;
thisCycle[pin] = debouncer[pin].read() ? inputOn : inputOff;
if (((requestStates) && (thisCycle[pin] != lastCycle[pin]))|| (thisCycle[pin] != lastCycle[pin])) {
lastCycle[pin] = thisCycle[pin];
// Invert input
if (invertArray[pin]) {
thisCycle[pin] = !thisCycle[pin];
}
// Serialize the message (input state)
doc.clear();
doc["command"] = "switchlight";
doc["idx"] = idx_inputArray[pin];
if (thisCycle[pin]) {
doc["switchcmd"] = "On";
} else {
doc["switchcmd"] = "Off";
}
// Send the message
mqttClient.beginMessage(inTopic);
serializeJson(doc, mqttClient);
mqttClient.endMessage();
// show serialization message
serializeJsonPretty(doc, myOutput);
Serial.println(myOutput);
// Serialize the message (output state)
doc.clear();
doc["command"] = "getdeviceinfo";
doc["idx"] = idx_inputArray[pin];
// Send the message
mqttClient.beginMessage(inTopic);
serializeJson(doc, mqttClient);
mqttClient.endMessage();
// show serialization message
serializeJsonPretty(doc, myOutput);
Serial.println(myOutput);
}
}
mqttClient.poll();
}
void onMqttMessage(int messageSize) {
// we received a message
Serial.print("Received a message with topic: '");
Serial.print(mqttClient.messageTopic());
Serial.print("', length: ");
Serial.print(messageSize);
Serial.println(" bytes:");
// deserialize the message
DynamicJsonDocument doc(messageSize);
DeserializationError err = deserializeJson(doc, mqttClient);
if (err) {
Serial.print("deserializeJson() failed with code: ");
Serial.println(err.f_str());
} else {
// show deserialization message
serializeJsonPretty(doc, myOutput);
Serial.println(myOutput);
// change output state
for (int pin = 0; pin < numberOutputs; pin++) {
if ((idx_outputArray[pin] == doc["idx"]) and (doc["switchType"] == switchType)) {
Serial.print("Incoming change for: ");
Serial.print((char*)doc["name"]);
Serial.print(" (idx: ");
Serial.print((int)doc["idx"]);
Serial.print("), new status: ");
Serial.println((int)doc["nvalue"]);
digitalWrite(outputArray[pin], doc["nvalue"] ? outputOn : outputOff);
break;
}
}
}
}
void startEthernet() {
// Initialize network
ethernetClient.stop();
Serial.println("Attempting to connect to network: ");
while (Ethernet.begin(mac) == 0) {
Serial.print(".");
delay(5000); // Wait 5 seconds, and try again
}
Serial.println("Connected to network");
Serial.print("IP address: ");
Serial.println(Ethernet.localIP());
}
void startBroker () {
// Initialize broker
mqttClient.stop();
Serial.println("Attempting to connect to broker");
unsigned int mqttConnection = 0;
while (!mqttClient.connect(broker, port)) {
Serial.print(".");
delay(5000); // Wait 5 seconds, and try again
mqttConnection +=1;
if (mqttConnection >= 5) {
Serial.print("MQTT connection failed! Error code = ");
Serial.println(mqttClient.connectError());
startEthernet();
return false;
}
}
Serial.println("Connected to broker");
mqttClient.subscribe(outTopic);
return true;
}