Saeid Moghadam
Published © MIT

Soifgo – Bluetooth & MQTT IoT Controller

Control devices via Bluetooth and MQTT using ESP8266

IntermediateWork in progress5 hours199
Soifgo – Bluetooth & MQTT IoT Controller

Things used in this project

Story

Read more

Schematics

ESP8266_mqtt

Atmega16_Bluetooth_5V

Code

esp8266_mqtt

Arduino
https://soifgo.github.io/soifgo/tutorials/server/Esp8266_wifi_mqtt/esp8266_mqtt.html
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <EEPROM.h>
#include <PubSubClient.h>

ESP8266WebServer server(80);
WiFiClient espClient;
PubSubClient client(espClient);

const char* mqtt_server = "test.mosquitto.org";
const int mqtt_port = 1883;
const char* mqtt_recv_topic = "soifgo_send";

String ssid = "";
String password = "";
String ap_pass = "";

unsigned long lastCheck = 0;
const unsigned long checkInterval = 15000;
int reconnectAttempts = 0;
const int maxReconnectAttempts = 4;

void handleRoot() {
  String mac = WiFi.macAddress();
  String html = "<h1>WiFi Setup</h1>"
                "<p><b>MAC Address:</b> " + mac + "</p>"
                "<form action='/savewifi' method='POST'>"
                "WiFi SSID: <input type='text' name='ssid'><br>"
                "WiFi Password: <input type='text' name='pass'><br>"
                "<input type='submit' value='Save WiFi'>"
                "</form><hr>"
                "<form action='/saveap' method='POST'>"
                "AP SSID: <b>ESP_Config</b><br>"
                "AP Password: <input type='text' name='ap_pass' placeholder='min 8 chars'><br>"
                "<input type='submit' value='Save AP'>"
                "</form><hr>"
                "<form action='/reset' method='POST'>"
                "<input type='submit' value='Reset EEPROM & Restart'>"
                "</form>";
  server.send(200, "text/html", html);
}

void handleSaveWiFi() {
  ssid = server.arg("ssid");
  password = server.arg("pass");

  for (int i = 0; i < 200; i++) EEPROM.write(i, 0);

  EEPROM.write(0, ssid.length());
  for (int i = 0; i < ssid.length(); i++) EEPROM.write(i+1, ssid[i]);

  EEPROM.write(100, password.length());
  for (int i = 0; i < password.length(); i++) EEPROM.write(i+101, password[i]);

  EEPROM.commit();

  server.send(200, "text/html", "WiFi Saved! Restarting...");
  delay(1500);
  ESP.restart();
}

void handleSaveAP() {
  ap_pass = server.arg("ap_pass");

  if (ap_pass.length() < 8) {
    server.send(200, "text/html", "Error: Password must be at least 8 characters!");
    return;
  }

  for (int i = 200; i < 400; i++) EEPROM.write(i, 0);

  EEPROM.write(300, ap_pass.length());
  for (int i = 0; i < ap_pass.length(); i++) EEPROM.write(i+301, ap_pass[i]);

  EEPROM.commit();

  server.send(200, "text/html", "AP Password Saved! Restarting...");
  delay(2000);
  ESP.restart();
}

void handleReset() {
  for (int i = 0; i < 512; i++) {
    EEPROM.write(i, 0);
  }
  EEPROM.commit();

  server.send(200, "text/html", "EEPROM cleared! Restarting...");
  delay(2000);
  ESP.restart();
}

void loadCredentials() {
  int ssidLen = EEPROM.read(0);
  ssid = "";
  for (int i = 0; i < ssidLen; i++) ssid += char(EEPROM.read(i+1));

  int passLen = EEPROM.read(100);
  password = "";
  for (int i = 0; i < passLen; i++) password += char(EEPROM.read(i+101));

  int apPassLen = EEPROM.read(300);
  ap_pass = "";
  for (int i = 0; i < apPassLen; i++) ap_pass += char(EEPROM.read(i+301));
}

void connectWiFi() {
  loadCredentials();

  bool connected = false;

  if (ssid.length() > 0) {
    WiFi.begin(ssid.c_str(), password.c_str());
    Serial.print("Connecting to saved WiFi: ");
    Serial.println(ssid);
    int retries = 0;
    while (WiFi.status() != WL_CONNECTED && retries < 5) {
      delay(500);
      Serial.print(".");
      retries++;
    }
    if (WiFi.status() == WL_CONNECTED) {
      Serial.println("\nConnected!");
      Serial.print("IP: ");
      Serial.println(WiFi.localIP());
      connected = true;
    } else {
      Serial.println("\nWiFi connect failed.");
    }
  }

  if (!connected) {
    if (ap_pass.length() < 8) ap_pass = "12345678";
    WiFi.softAP("ESP_Config", ap_pass.c_str());
    Serial.println("Started AP: ESP_Config, password: " + ap_pass);
    Serial.print("AP IP: ");
    Serial.println(WiFi.softAPIP());
  }
}

void mqttCallback(char* topic, byte* payload, unsigned int length) {
  String message;
  for (unsigned int i = 0; i < length; i++) {
    message += (char)payload[i];
  }
  if (String(topic) == mqtt_recv_topic) {
    Serial.println(message);
  }
}

bool reconnectMQTT() {
  if (!client.connected()) {
    String clientId = "ESP8266Client-" + String(ESP.getChipId());
    if (client.connect(clientId.c_str())) {
      client.subscribe(mqtt_recv_topic);
      Serial.println("MQTT connected");
      reconnectAttempts = 0;
      return true;
    } else {
      reconnectAttempts++;
      Serial.println("MQTT reconnect failed");
      return false;
    }
  }
  return true;
}

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

  connectWiFi();

  server.on("/", handleRoot);
  server.on("/savewifi", handleSaveWiFi);
  server.on("/saveap", handleSaveAP);
  server.on("/reset", handleReset);
  server.begin();

  client.setServer(mqtt_server, mqtt_port);
  client.setCallback(mqttCallback);
}

void loop() {
  server.handleClient();

  if (WiFi.status() == WL_CONNECTED) {
    if (!client.connected()) {
      reconnectMQTT();
    }
    client.loop();
  }

  if (millis() - lastCheck > checkInterval) {
    lastCheck = millis();

    if (WiFi.status() != WL_CONNECTED) {
      Serial.println("WiFi lost  reconnecting...");
      connectWiFi();
    }

    if (!client.connected()) {
      if (!reconnectMQTT() && reconnectAttempts >= maxReconnectAttempts) {
        Serial.println("Too many fails  Restarting...");
        ESP.restart();
      }
    }
  }



  static String serialBuffer = "";
  while (Serial.available()) {
    char c = Serial.read();
    if (c == '\n') {
      serialBuffer.trim();
      if (serialBuffer.length() > 0) {
        int sepIndex = serialBuffer.indexOf(':');
        if (sepIndex > 0) {
          String topicPart   = serialBuffer.substring(0, sepIndex);
          String payloadPart = serialBuffer.substring(sepIndex + 1);
          String fullTopic   = "soifgo_" + topicPart;
          client.publish(fullTopic.c_str(), payloadPart.c_str());
        }
      }
      serialBuffer = "";
    } else {
      serialBuffer += c;
    }
  }
}

Atmega16_bluetooth_bascom

VB.NET
$regfile = "m16adef.dat"
$crystal = 11059200

Config Adc = Single , Prescaler = Auto , Reference = Avcc
Config Timer1 = Pwm , Pwm = 10 , Compare_a_pwm = Clear_up , Compare_b_pwm = Clear_up , Prescale = 1
Declare Sub Red

CONFIG PORTB=OUTPUT
   Portb = 0
Config Portc.0 = Input                                      'in key 1
Ddrc.0 = 0 : Portc.0 = 1

 Config Portc.1 = Input                                     'in key 2
Ddrc.1 = 0 : Portc.1 = 1

$baud = 9600

Enable Interrupts

 Config Serialin = Buffered , Size = 41 , Bytematch = 13

Dim Text As String * 40
Dim Text2 As String * 4
Dim Text3 As String * 5
DIM TEMP1,LastTemp1 AS WORD
Dim Temp2,LastTemp2 As Word
Dim Volt,pwm1aa As Word
Dim Volt2,LastVolt2 As Single
Dim Step1 As Byte
Dim T1 , I As Byte
dim t2 as bit
dim pc,lastpc,pb,lastpb as byte
config watchdog=2048
start watchdog
 Readeeprom portb , 1
  Waitms 1
  Readeeprom pwm1aa , 3
  Waitms 1
  Open "comd.6:9600,8,n,1" For Output As #1

  Print #1 , "soifgo"
pwm1a=pwm1aa
Main:
waitms 30
  Incr Step1

reset watchdog

    If Step1 >8 Then Step1 = 1


    Select Case Step1

        Case 1

            Volt = Getadc(0)
            Volt2 = Volt / 204.8
               If Volt2 <> Lastvolt2 Then
                   Print "volt:" ; Fusing(volt2 , "#.##")
                   Lastvolt2 = Volt2
               End If
        Case 2
              Temp1 = Getadc(1)
               If Temp1 <> Lasttemp1 Then
                   Print "temp1" ; ":" ; Temp1
                   Lasttemp1 = Temp1
               End If
        Case 3
            Temp2 = Getadc(2)
               If Temp2 <> Lasttemp2 Then
                   Print "temp2" ; ":" ; Temp2
                   Lasttemp2 = Temp2
               End If
        Case 4
           Pb = Portb
               If Pb <> Lastpb Then
                  Print "portb" ; ":" ; Bin(portb)
                  Lastpb = Pb
               End If
        Case 5
                 Pc = Portc
               If Pc <> Lastpc Then
                  Print "pinc" ; ":" ; Pinc.0 ; Pinc.1
                  Lastpc = Pc
               End If

    End Select




Goto Main

Serial0charmatch:
 Waitms 40
Input Text

if text <> "" then call Red
Return


Sub Red
  Reset Watchdog

  Text = Trim(text)
  Text = Ltrim(text)
     Disable Interrupts
 ' Print #1 , ">" ; Text ; "<"
      If Instr(text , "rang") > 0 Then

       Print #1 , Mid(text , 6 , 36)

       End If
    Enable Interrupts
   If Instr(text , "pwm1a") > 0 Then
      Text3 = Mid(text , 7 , 4)
      Pwm1a = Val(text3)
      Writeeeprom pwm1a , 3
   End If

  If Instr(text , "port") > 0 Then
     Text2 = Mid(Text , 7 , 1)
     Text = Mid(text , 5 , 1)


      if text2="0" then t2=0
      if text2="1" then t2=1

      t1=val(text)

      If T1 < 8 Then Portb.t1 = T2

   If T1 = 9 Then

          if t2=1 then
            Portb = 255
             For I = 0 To 7
              Print "port" ; I ; ":1"
              Waitms 50
             Next
          End If

        if t2=0 then
          portb=0
          for i=0 to 7
           Print "port" ; I ; ":0"
           waitms 50
          next
        end if


   end if
    Writeeeprom Portb , 1

  End If

   Text = ""
   Text2 = ""
   Text3 = ""
   T1 = 222
   T2 = 0
   Clear Serialin


End Sub

atmega16_report_esp8266

VB.NET
$regfile = "m16adef.dat"
$crystal = 11059200

Config Adc = Single , Prescaler = Auto , Reference = Avcc
Config Timer1 = Pwm , Pwm = 10 , Compare_a_pwm = Clear_up , Compare_b_pwm = Clear_up , Prescale = 1
Declare Sub Red

CONFIG PORTB=OUTPUT
   Portb = 0
Config Portc.0 = Input                                      'in key 1
Ddrc.0 = 0 : Portc.0 = 1

 Config Portc.1 = Input                                     'in key 2
Ddrc.1 = 0 : Portc.1 = 1

$baud = 115200

Enable Interrupts

 Config Serialin = Buffered , Size = 41 , Bytematch = 13

Dim Text As String * 40
Dim Text2 As String * 4
Dim Text3 As String * 5
DIM TEMP1,LastTemp1 AS WORD
Dim Temp2,LastTemp2 As Word
Dim Volt,pwm1aa As Word
Dim Volt2,LastVolt2 As Single
Dim Step1 As Byte
dim p,t1,i as byte
dim t2 as bit
dim pc,lastpc,pb,lastpb as byte
config watchdog=2048
start watchdog
 Readeeprom portb , 1
  Waitms 1
  Readeeprom pwm1aa , 3
  Waitms 1
  Open "comd.6:9600,8,n,1" For Output As #1

  Print #1 , "soifgo"
pwm1a=pwm1aa
Main:
waitms 100
  Incr Step1

reset watchdog

    If Step1 > 16 Then Step1 = 1


    Select Case Step1

        Case 2

            Volt = Getadc(0)
            Volt2 = Volt / 204.8
               If Volt2 <> Lastvolt2 Then
                   Print "#volt:" ; Fusing(volt2 , "#.##") ; "*"
                   Lastvolt2 = Volt2
               End If
        Case 4
              Temp1 = Getadc(1)
               If Temp1 <> Lasttemp1 Then
                   Print "#temp1" ; ":" ; Temp1 ; "*"
                   Lasttemp1 = Temp1
               End If
        Case 6
            Temp2 = Getadc(2)
               If Temp2 <> Lasttemp2 Then
                   Print "#temp2" ; ":" ; Temp2 ; "*"
                   Lasttemp2 = Temp2
               End If
        Case 8
           Pb = Portb
               If Pb <> Lastpb Then
                  Print "#portb" ; ":" ; Bin(portb) ; "*"
                  Lastpb = Pb
               End If
        Case 10
                 Pc = Portc
               If Pc <> Lastpc Then
                  Print "#pinc" ; ":" ; Pinc.0 ; Pinc.1 ; "*"
                  Lastpc = Pc
               End If

        Case 12
               incr p
               if p>7 then p=0
                Print "#GET:port";p;"*"
    End Select




Goto Main

Serial0charmatch:
 waitms 20
Input Text

if text <> "" then call Red
Return


Sub Red
  Reset Watchdog

  Text = Trim(text)
  Text = Ltrim(text)

  'Print #1 , ">";Text;"<"
      If Instr(text , "rang") > 0 Then
      Disable Interrupts
       Print #1 , Mid(text , 6 , 36)
        Enable Interrupts
       End If

   If Instr(text , "pwm1a") > 0 Then
      Text3 = Mid(text , 7 , 4)
      Pwm1a = Val(text3)
      Writeeeprom pwm1a , 3
   End If

  If Instr(text , "port") > 0 Then
     Text2 = Mid(Text , 7 , 1)
     Text = Mid(text , 5 , 1)


      if text2="0" then t2=0
      if text2="1" then t2=1

      t1=val(text)

      If T1 < 8 Then Portb.t1 = T2

   If T1 = 9 Then

          if t2=1 then
            Portb = 255
             For I = 0 To 7
              Print "#port" ; I ; ":1*"
              Waitms 50
             Next
          End If

        if t2=0 then
          portb=0
          for i=0 to 7
           Print  "#port";i ; ":0*"
           waitms 50
          next
        end if


   end if
    Writeeeprom Portb , 1

  End If

   Text = ""
   Text2 = ""
   Text3 = ""
   T1 = 222
   T2 = 0
   Clear Serialin


End Sub

Credits

Saeid Moghadam
3 projects • 1 follower
Electrical & electronics engineer sharing simple beginner‑level projects. Still learning, still improving. Feedback helps me grow.

Comments