B4R Tutorial MQTT controlling 8 relays, WeMos D1 mini WiFi, Android 4G

Here is a short tutorial on how to control an 8 channel relay module via MQTT. Below you will find both the WeMos and Android source codes needed to get started. The relay module is connected to a 74HC595 shift register that in turn is connected by only 3 wires to a WeMos D1 mini based microcontroller. The microcontroller receives MQTT messages/commands through WiFi, the MQTT messages/commands are send by an Android phone through 4G.

So what is MQTT?
Well the quick and dirty answer to that question is that MQTT (Message Queuing Telemetry Transport) is an ISO standard, lightweight, low-bandwidth, machine to machine, TCP/IP publish or subscribe messaging protocol which is great for controlling IoT (Internet of Things) devices from over the internet.

There are plenty of free online MQTT brokers that you can choose from, I personally use a service called CloudMQTT and they can be found right here...
Please note: For this screen shot I sent all the 'Messages' in plain readable text for testing purposes
Untitled-2.png

Send message - Android source code
Libraries: ByteConverter and jMQTT

B4X:
Sub Process_Globals
    Private MQTT As MqttClient
    Private MQTTUser As String = "xxxxxxx"
    Private MQTTPassword As String = "_xxxxxxx"
    Private MQTTServerURI As String = "tcp://m21.cloudmqtt.com:14925"
    Private BC As ByteConverter
End Sub

Sub Globals
    Private lblStatus As Label
    Private SpnTimerMinutes As Spinner
End Sub

Sub Activity_Create(FirstTime As Boolean)
    If FirstTime Then
        CallSub(Me, MQTT_Connect)
    End If

    Activity.LoadLayout("Relay_Switches")

    'Populate Spinner With Minutes
    For i = 10 To 60 Step 10
        SpnTimerMinutes.Add(i)
    Next
End Sub

Sub Activity_Resume
End Sub

Sub Activity_Pause (UserClosed As Boolean)
End Sub

'Connect to CloudMQTT broker
Sub MQTT_Connect
        Dim ClientId As String = Rnd(0, 999999999) 'create a unique id
        MQTT.Initialize("MQTT", MQTTServerURI, ClientId)

        Dim ConnOpt As MqttConnectOptions
            ConnOpt.Initialize(MQTTUser, MQTTPassword)
        MQTT.Connect2(ConnOpt)
End Sub

Sub MQTT_Connected (Success As Boolean)
    If Success = False Then
        Log(LastException)
        lblStatus.Text = "Error connecting"
    Else
        lblStatus.Text = " - Connected to broker"
        MQTT.Subscribe("drawers/#", 0)
    End If
End Sub

Private Sub MQTT_Disconnected
    lblStatus.Text = " - Disconnected from broker"
End Sub

Private Sub MQTT_MessageArrived (Topic As String, Payload() As Byte)
End Sub

'PLEASE NOTE:
'ALTERNATIVELY YOU CAN ALSO CREATED BUTTONS DYNAMICALLY ON THE FLY AND USED A SENDER TO MONITOR BUTTON CLICKS
Sub ToggleButton0_CheckedChange(Checked As Boolean)
    MQTT.Publish("Relay_0", BC.StringToBytes(Checked, "utf8"))
End Sub

Sub ToggleButton1_CheckedChange(Checked As Boolean)
    MQTT.Publish("Relay_1", BC.StringToBytes(Checked, "utf8"))
End Sub

Sub ToggleButton2_CheckedChange(Checked As Boolean)
    MQTT.Publish("Relay_2", BC.StringToBytes(Checked, "utf8"))
End Sub

Sub ToggleButton3_CheckedChange(Checked As Boolean)
    MQTT.Publish("Relay_3", BC.StringToBytes(Checked, "utf8"))
End Sub

Sub ToggleButton4_CheckedChange(Checked As Boolean)
    MQTT.Publish("Relay_4", BC.StringToBytes(Checked, "utf8"))
End Sub

Sub ToggleButton5_CheckedChange(Checked As Boolean)
    MQTT.Publish("Relay_5", BC.StringToBytes(Checked, "utf8"))
End Sub

Sub ToggleButton6_CheckedChange(Checked As Boolean)
    MQTT.Publish("Relay_6", BC.StringToBytes(Checked, "utf8"))
End Sub

Sub ToggleButton7_CheckedChange(Checked As Boolean)
    MQTT.Publish("Relay_7", BC.StringToBytes(Checked, "utf8"))
End Sub

Sub BtnStart_Click
    'Code to come shortly for auto power off relays...
End Sub

Receive message - WeMos D1 mini source code
Libraries: rESP8266, rESP8266WiFi, rMQTT and rRandomAccessFile

B4X:
'WIRE LEGEND for 74HC595 shift register
'8 GND = GND
'16 Vcc = 5V
'14 = D1
'12 = GND
'12 = D2
'11 = D3
'10 = 5V
'QA to QH is connected to relays 7 to 0

Sub Process_Globals
    'These global variables will be declared once when the application starts.
    'Public variables can be accessed from all modules.

    Public Serial1 As Serial

    Private AStream As AsyncStreams
    Private WiFi As ESP8266WiFi
    Private WiFiStr As WiFiSocket
    Private MQTT As MqttClient
    Private MQTTOpt As MqttConnectOptions
    Private MQTTUser As String = "xxxxxxx"
    Private MQTTPassword As String = "_xxxxxxx"
    Private MQTTHostName As String = "m21.cloudmqtt.com"
    Private MQTTPort As Int = 14925
    Private DS, STCP, SHCP As Pin
    Private Relays As Int = 8
    Private Registers(Relays) As Boolean
    Private ESPin As D1Pins
End Sub

Private Sub AppStart
    Serial1.Initialize(115200)
    Delay(1000)
    Log("AppStart")

    DS.Initialize(ESPin.D1, DS.MODE_OUTPUT) 'Arduino Pin 8, SR Pin 14 Serial In
    STCP.Initialize(ESPin.D2, STCP.MODE_OUTPUT) 'Arduino Pin 11, SR Pin 12 RCK
    SHCP.Initialize(ESPin.D3, SHCP.MODE_OUTPUT) 'Arduino Pin 12, SR Pin 11 Serial Clock

    'Clear Register Values
    ClearAllReg

    AStream.Initialize(Serial1.Stream, "Astream_NewData", "Astream_Error")

    'Connect to local WiFi Access Point
    WiFi.Connect2("Access Point", "Access Point Password")
    If WiFi.IsConnected Then Log("Connected to WiFi, Local IP ", WiFi.LocalIp) Else Log("Not Connected to WiFi")

    'Connect to CloudMQTT broker
    Dim ClientId As String = Rnd(0, 999999999) 'create a unique id
    MQTT.Initialize2(WiFiStr.stream, MQTTHostName, MQTTPort, ClientId, "MQTT_MessageArrived", "MQTT_Disconnected")
    MQTTOpt.Initialize(MQTTUser, MQTTPassword)
    MQTT_Connect(0)
End Sub

Sub MQTT_MessageArrived (Topic As String, Payload() As Byte)
    Log("Topic = ", Topic, " and Payload = ", Payload)

    Dim State As Boolean
    Dim BC As ByteConverter
    If BC.StringFromBytes(Payload) = "true" Then State = True Else State = False

    Select Case Topic
        Case "Relay_0"
            Registers(0) = Not(State)
        Case "Relay_1"
            Registers(1) = Not(State)
        Case "Relay_2"
            Registers(2) = Not(State)
        Case "Relay_3"
            Registers(3) = Not(State)
        Case "Relay_4"
            Registers(4) = Not(State)
        Case "Relay_5"
            Registers(5) = Not(State)
        Case "Relay_6"
            Registers(6) = Not(State)
        Case "Relay_7"
            Registers(7) = Not(State)
    End Select

    WriteToReg
End Sub

Sub MQTT_Connect(Unused As Byte)
    If MQTT.Connect = False Then
        Log("Trying to connect to broker")
        MQTT.Connect2(MQTTOpt)
        CallSubPlus("MQTT_Connect", 1000, 0)
    Else
        Log("Connected to broker")

        For i = 0 To Relays - 1
            MQTT.Subscribe(JoinStrings(Array As String("Relay_", i)), 0)
        Next
    End If
End Sub

Sub MQTT_Disconnected
    Log("Disconnected")
    MQTT.Close
    MQTT_Connect(0)
End Sub

Sub Astream_NewData (Buffer() As Byte)
    Log("Received: ", Buffer)
End Sub

Sub AStream_Error
    Log("error")
End Sub

'Write To Registers
Private Sub WriteToReg()
    STCP.DigitalWrite(False)

    Dim i As Int = 0
    Do While i <= Relays - 1
        SHCP.DigitalWrite(False)
        DS.DigitalWrite(Registers(i))
        SHCP.DigitalWrite(True)
        i = i + 1
    Loop

    STCP.DigitalWrite(True)
End Sub

'Clear All Registers
Private Sub ClearAllReg()
    Dim i As Int = Relays - 1
    Do While i >= 0
        Registers(i) = True 'True = NO
        i = i - 1
        WriteToReg
    Loop
End Sub

How to wire up the WeMos D1 mini to the shift register, the white wires connects to relays 7 to 0
Shift-register-WeMos-8-Relays_bb.png


YouTube video of an Android device controlling 8 relays over 4G

Enjoy...
 
Last edited:

Peter Simpson

Expert
Licensed User
Longtime User
So @Erel, I finally got around to updating both my B4A and B4R code to use B4RSerializator, it works great. I also got rid of all the button click sub events and replaced them all with a single sub linking all the buttons via the same event name, so now I can just use a sender in the one sub. Doing it this way makes for a neater solution, and obviously my code is easier to maintain in just one sub. I have actually integrated this irrigation system into my garden, this includes sprinklers, pumps, hoses the lot, it all works great :)

Cheers...
 
Last edited:
Dear Peter, you did a wonderful project that I really enjoyed. Here follow you my project a little similar to yours with the management through Google Assistant. Yes, as 4 relays are few I tried to change the project to manage 24 relays via SN74hc595, but I did not succeed.
By chance would you be so kind as to be able to modify my shetck in order to use it with the shift register as you did?
Thank you so much .

---------------------------------------------------------------

#include <ESP8266WiFi.h>
#include "Adafruit_MQTT.h"
#include "Adafruit_MQTT_Client.h"

#define Relay1 D1
#define Relay2 D2
#define Relay3 D3
#define Relay4 D4

#define WLAN_SSID " ---- " // Your SSID
#define WLAN_PASS " ---- " // Your password

/************************* Adafruit.io Setup *********************************/

#define AIO_SERVER "io.adafruit.com" //Adafruit Server
#define AIO_SERVERPORT 1883
#define AIO_USERNAME " ---- " // Username
#define AIO_KEY " ----- " // Auth Key

//WIFI CLIENT
WiFiClient client;

Adafruit_MQTT_Client mqtt(&client, AIO_SERVER, AIO_SERVERPORT, AIO_USERNAME, AIO_KEY);

Adafruit_MQTT_Subscribe Light1 = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME"/feeds/Relay1"); // Feeds name should be same everywhere
Adafruit_MQTT_Subscribe Light2 = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "/feeds/Relay2");
Adafruit_MQTT_Subscribe Light3 = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "/feeds/Relay3");
Adafruit_MQTT_Subscribe Light4 = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "/feeds/Relay4");

void MQTT_connect();

void setup() {
Serial.begin(115200);

pinMode(Relay1, OUTPUT);
pinMode(Relay2, OUTPUT);
pinMode(Relay3, OUTPUT);
pinMode(Relay4, OUTPUT);

// Connect to WiFi access point.
Serial.println(); Serial.println();
Serial.print("Connecting to ");
Serial.println(WLAN_SSID);

WiFi.begin(WLAN_SSID, WLAN_PASS);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println();

Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
mqtt.subscribe(&Light1);
mqtt.subscribe(&Light3);
mqtt.subscribe(&Light2);
mqtt.subscribe(&Light4);
}

void loop() {
MQTT_connect();


Adafruit_MQTT_Subscribe *subscription;
while ((subscription = mqtt.readSubscription(20000))) {
if (subscription == &Light1) {
Serial.print(F("Got: "));
Serial.println((char *)Light1.lastread);
int Light1_State = atoi((char *)Light1.lastread);
digitalWrite(Relay1, Light1_State);

}
if (subscription == &Light2) {
Serial.print(F("Got: "));
Serial.println((char *)Light2.lastread);
int Light2_State = atoi((char *)Light2.lastread);
digitalWrite(Relay2, Light2_State);
}
if (subscription == &Light3) {
Serial.print(F("Got: "));
Serial.println((char *)Light3.lastread);
int Light3_State = atoi((char *)Light3.lastread);
digitalWrite(Relay3, Light3_State);
}
if (subscription == &Light4) {
Serial.print(F("Got: "));
Serial.println((char *)Light4.lastread);
int Light4_State = atoi((char *)Light4.lastread);
digitalWrite(Relay4, Light4_State);

}
}


}

void MQTT_connect() {
int8_t ret;

if (mqtt.connected()) {
return;
}

Serial.print("Connecting to MQTT... ");

uint8_t retries = 3;

while ((ret = mqtt.connect()) != 0) {
Serial.println(mqtt.connectErrorString(ret));
Serial.println("Retrying MQTT connection in 5 seconds...");
mqtt.disconnect();
delay(5000);
retries--;
if (retries == 0) {
while (1);
}
}
Serial.println("MQTT Connected!");

}
 

Peter Simpson

Expert
Licensed User
Longtime User
Hello @Diego La Mattina, welcome to the community, sorry but I don't use Google assist even though I've been meaning to do so.

The N74HC595 is an 8-bit shift register, you would need 3 x N74HC595 shift registers to switch 24 relays. The best thing about using shift registers is that you can easily daisy chain multiple shift registers together to switch multiple relays or LEDs for example. For example you can connect 2 N74HC595 shift registers together to switch 16 relays or 3 N74HC595 shift registers to switch 24 relays. To connect one N74HC595 to another N74HC595 you only need positive, ground and two extra wires which connects the output clock pin to the input clock pin and the h-prime pin to the data pin from one N74HC595 to the other N74HC595.

Basically what I'm saying is that you need 3 * N74HC595 shift registers to do what you need.

BTW you should be using B4R, you will find it easier, even though the code you posted looks easy enouhg to work with.

Anyway, I will give you a couple of nice tips, starting with connect 3 * N74HC595 connect then together, there are simple instruction on the net on how to do that.

In my second block of code above, you just need to change
B4X:
Private Relays As Int = 8
to
B4X:
Private Relays As Int = 24
then you can add more Select Case Topic, which I would not do.
B4X:
Case "Relay_7"
    Registers(7) = Not(State)
If you are going to control 24 relays then I would not use Select Case, I would write a small but tidy look to keep the code nice and tidy, it will also keep the sub shorter too.

If you have not done so already, I highly recommend that you download and install B4R, it's 100% free to use and you will find it a lot easier to get to grips with if you are not proficient at programming in C/C++.

Give it a free, it's free...
 
@Peter Simpson Thanks a lot for answering me. Unfortunately I am a beginner with the programming of C is I thought it was easy to be able to change through the shift register so as to be able to expand the outputs of NodeMcu, but when I see it seems to me a complex thing.
 

Peter Simpson

Expert
Licensed User
Longtime User
@Peter Simpson Thanks a lot for answering me. Unfortunately I am a beginner with the programming of C is I thought it was easy to be able to change through the shift register so as to be able to expand the outputs of NodeMcu, but when I see it seems to me a complex thing.

It's not really complex.
BTW this forum IS NOT for c development, our community uses a language called B4X which is basically a turbo charged updated version of BASIC which can be used to develop Android or iOS (Apple) apps, desktop or web solutions, Arduino or even Pi solution too, all using information one language called B4X, maybe you should look more into it.

I have lately learned C++ and C# but I don't used them for anything, only for checking routines found using Google searches, then I convert code to either B4X or VB.Net depending on the application I'm building for clients.

Back to your issue, if you download B4R in the link at the top of this page and install it as it's 200% free, we on this community will be more than willing to help you get your project up and running. Using shift registers is extremely simple to do, looking at my code above proves that.

BTW, if you are learning C, how did you manage to find this great forum?
 
Last edited:
@Peter Simpson Well dear Peter, I understand I'll try to make the tutorial you've shown modifying as you described to manage the 24 relays. I registered for a free CloudMQTT only 5 users can manage the relays. Now in your tutorial in the sketch I have to enter the access data to the CloudMQTT (email + password for access?). After that how can I view the screen on my smartphone as shown in the video?
 

Peter Simpson

Expert
Licensed User
Longtime User
@Peter SimpsonAfter that how can I view the screen on my smartphone as shown in the video?

Hello @Diego La Mattina,
First copy and past my code into B4R and B4A, download the trial version of B4A, then try to replicate by results which should be simple for you to do as it's just copy and paste the code and follow the diagram above. Once you manage to get my example project above working, you should then try to double your relays from 8 to 16.

I didn't want to create a diagram just for you ;), so here is a diagram taken from the Arduino forum, it's the same thing but instead of connection LED's through resistors, you will be connecting relay packs.

ShftOut_Schm2.jpg


ShftOutExmp2_3.gif


For Android app I developed a bespoke app just for my needs, but you said that you wanted to use Google Assistant. You now have three viable options.
  1. B4A
  2. Android Studio
  3. Eclipse
I personally always use the very capable B4A for developing my Android app, actually I use B4A to develop all of my Android apps.

Google assistant integration is not something that I've looked at, but I know that Erel has posted some code on the forum somewhere that uses an intent. You should download the trial version of B4A and then try to make yourself a basic 'Hello World' app with a button press, mine was actually 'Hello Joanne' lol...

Any, keep posting if you have any more Arduino or ESP questions.
If you have any B4A questions, then post your questions on the B4A part of this forum.
 
@Peter Simpson Well well very well you were formidable in the explanation Peter. Yes, I already looked at the wiring diagram as you had sent me, the application I prefer to use the same as yours, I give up Google Assistant. If you kindly had a small guide to create the application like yours I am very grateful to you so I then extend it to the relays I need. Thank you very much for your attention I can not wait to finish this project, I'm passionate about it.
 

Peter Simpson

Expert
Licensed User
Longtime User
@Peter Simpson Well well very well you were formidable in the explanation Peter. Yes, I already looked at the wiring diagram as you had sent me, the application I prefer to use the same as yours, I give up Google Assistant. If you kindly had a small guide to create the application like yours I am very grateful to you so I then extend it to the relays I need. Thank you very much for your attention I can not wait to finish this project, I'm passionate about it.
Hello,

The code for the demo app I wrote is in the very first post.
 
So @Erel, I finally got around to updating both my B4A and B4R code to use B4RSerializator, it works great. I also got rid of all the button click sub events and replaced them all with a single sub linking all the buttons via the same event name, so now I can just use a sender in the one sub. Doing it this way makes for a neater solution, and obviously my code is easier to maintain in just one sub. I have actually integrated this irrigation system into my garden, this includes sprinklers, pumps, hoses the lot, it all works great :)

Cheers...
Dear Peter Simpson,

I just started practically with ESP with Great B4X. I have learnt basic concept from your post and hopefully it is first program which I will download and let see what happen. Even I will not use 74HC595 and control outputs directly on WeMos to make basic concepts clear.

First question: Did you updated program with B4RSerializator in the first post as Erel suggested which you did successfully.

Second question: Please can you suggest what to change for local MQTT client and Broker in B4A app. I wanted to make it local without internet connection needed. Once I holds grip with step by step small steps then I will add function. I just want to learn basic concepts so that I could do myself and only ask the questions which are not solved. Thanks a lot.
 

shreshth1911

New Member
it's easy to write the code to make it work in B4J. 99,9% of the code is the same as B4A, start with creating a project in B4XPage
hello sir ,I tried your method using b4xpages. BUT i am not able to control the esp using the code of b4a on b4j . please kindly provide the code if possible
 
Top