Adding 2 switches to D1 Mini Pro

Hello Experts

I have a D1 Mini Pro that uses MQTT to publish 3 sensors to Home Assistant, I want to also use it to publish two switches that I want to add to D4 and D5 pins or any other pins that I can use on the D1 Mini. I did not write the following code but I do understand it a bit, however, I do not know where and how to add the two switches nor that I know how to associate the switches with any 2 pins on the D1 Mini, your help will be very much appreciated. Cheers

Here is the full code

`

////////////////////////////////////////////////////////////////////////////////////////////////////
// Modify these values for your environment
const char *wifiSSID = "";                  // Your WiFi network name
const char *wifiPassword = "";          // Your WiFi network password
const char *otaPassword = "";                       // OTA update password
const char *mqttServer = "192.168.0.205";            // Your MQTT server IP address
const char *mqttUser = "mqttu";                          // mqtt username, set to "" for no user
const char *mqttPassword = "";                      // mqtt password, set to "" for no password
const String mqttNode = "MPSPresenceAntenna";              // Your unique hostname for this device
const String mqttDiscoveryPrefix = "homeassistant"; // Home Assistant MQTT Discovery, see https://home-assistant.io/docs/mqtt/discovery/
////////////////////////////////////////////////////////////////////////////////////////////////////

// Home Assistant MQTT Discovery, see https://home-assistant.io/docs/mqtt/discovery/
// We'll create one binary_sensor device to track MQTT connectivity
const String mqttDiscoBinaryStateTopic = mqttDiscoveryPrefix + "/binary_sensor/" + mqttNode + "/state";
const String mqttDiscoBinaryConfigTopic = mqttDiscoveryPrefix + "/binary_sensor/" + mqttNode + "/config";
// And a sensor for WiFi signal strength
const String mqttDiscoSignalStateTopic = mqttDiscoveryPrefix + "/sensor/" + mqttNode + "-signal/state";
const String mqttDiscoSignalConfigTopic = mqttDiscoveryPrefix + "/sensor/" + mqttNode + "-signal/config";
// And a sensor for device uptime
const String mqttDiscoUptimeStateTopic = mqttDiscoveryPrefix + "/sensor/" + mqttNode + "-uptime/state";
const String mqttDiscoUptimeConfigTopic = mqttDiscoveryPrefix + "/sensor/" + mqttNode + "-uptime/config";

// The strings below will spill over the PubSubClient_MAX_PACKET_SIZE 128
// You'll need to manually set MQTT_MAX_PACKET_SIZE in PubSubClient.h to 512
const String mqttDiscoBinaryConfigPayload = "{\"name\": \"" + mqttNode + "\", \"device_class\": \"connectivity\", \"state_topic\": \"" + mqttDiscoBinaryStateTopic + "\"}";
const String mqttDiscoSignalConfigPayload = "{\"name\": \"" + mqttNode + "-signal\", \"state_topic\": \"" + mqttDiscoSignalStateTopic + "\", \"unit_of_measurement\": \"dBm\", \"value_template\": \"{{ value }}\"}";
const String mqttDiscoUptimeConfigPayload = "{\"name\": \"" + mqttNode + "-uptime\", \"state_topic\": \"" + mqttDiscoUptimeStateTopic + "\", \"unit_of_measurement\": \"msec\", \"value_template\": \"{{ value }}\"}";

// Set the signal strength and uptime reporting interval in milliseconds
const unsigned long reportInterval = 5000;
unsigned long reportTimer = millis();

// Set LED "twinkle" time for maximum daylight visibility
const unsigned long twinkleInterval = 50;
unsigned long twinkleTimer = millis();

#define HornPin D4
#define HazardPin D5

#include <ESP8266WiFi.h>
#include <ESP8266mDNS.h>
#include <WiFiUdp.h>
#include <ArduinoOTA.h>
#include <PubSubClient.h>

WiFiClient wifiClient;
PubSubClient mqttClient(wifiClient);

//IPAddress staticIP(192,168,0,6);
//IPAddress gateway(192,168,0,1);
//IPAddress subnet(255,255,255,0);

////////////////////////////////////////////////////////////////////////////////////////////////////
// System setup
void setup()
{
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(HornPin, OUTPUT);
  pinMode(HazardPin, OUTPUT);  
  digitalWrite(LED_BUILTIN, HIGH);
  Serial.begin(115200);

  Serial.println("\nHardware initialized, starting program load");

  // Start up networking
  setupWifi();

  // Create server and assign callbacks for MQTT
  mqttClient.setServer(mqttServer, 1883);
  mqttClient.setCallback(mqtt_callback);
  mqttConnect();

  // Start up OTA
  if (otaPassword[0])
  {
    setupOTA();
  }

  Serial.println("Initialization complete\n");
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Main execution loop
void loop()
{
  // check WiFi connection
  if (WiFi.status() != WL_CONNECTED)
  {
    setupWifi();
  }

  // check MQTT connection
  if (!mqttClient.connected())
  {
    mqttConnect();
  }

  // MQTT client loop
  if (mqttClient.connected())
  {
    mqttClient.loop();
  }

  // LED twinkle
  if (mqttClient.connected() && ((millis() - twinkleTimer) >= twinkleInterval))
  {
    digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
    twinkleTimer = millis();
  }

  // Report signal strength and uptime
  if (mqttClient.connected() && ((millis() - reportTimer) >= reportInterval))
  {
    String signalStrength = String(WiFi.RSSI());
    String uptimeTimer = String(millis());
    mqttClient.publish(mqttDiscoSignalStateTopic.c_str(), signalStrength.c_str());
    mqttClient.publish(mqttDiscoUptimeStateTopic.c_str(), uptimeTimer.c_str());
    reportTimer = millis();
  }

  // OTA loop
  if (otaPassword[0])
  {
    ArduinoOTA.handle();
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Functions

////////////////////////////////////////////////////////////////////////////////////////////////////
// Handle incoming commands from MQTT
void mqtt_callback(char *topic, byte *payload, unsigned int payloadLength)
{
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// Connect to WiFi
void setupWifi()
{
  Serial.print("Connecting to WiFi network: " + String(wifiSSID));
  WiFi.hostname(mqttNode.c_str());
  WiFi.mode(WIFI_STA);
  WiFi.setSleepMode(WIFI_NONE_SLEEP);
  //WiFi.config(staticIP, gateway, subnet);
  WiFi.begin(wifiSSID, wifiPassword);

  while (WiFi.status() != WL_CONNECTED)
  {
    delay(1);
  }
  Serial.println("\nWiFi connected successfully and assigned IP: " + WiFi.localIP().toString());
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// MQTT connection and subscriptions
void mqttConnect()
{
  digitalWrite(LED_BUILTIN, HIGH);
  Serial.println("Attempting MQTT connection to broker: " + String(mqttServer));
  // Attempt to connect to broker, setting last will and testament
  if (mqttClient.connect(mqttNode.c_str(), mqttUser, mqttPassword, mqttDiscoBinaryStateTopic.c_str(), 1, 1, "OFF"))
  {
    // when connected, record signal strength and reset reporting timer
    String signalStrength = String(WiFi.RSSI());
    reportTimer = millis();
    String uptimeTimer = String(millis());
    // publish MQTT discovery topics and device state
    Serial.println("MQTT discovery connectivity config: [" + mqttDiscoBinaryConfigTopic + "] : [" + mqttDiscoBinaryConfigPayload + "]");
    Serial.println("MQTT discovery connectivity state: [" + mqttDiscoBinaryStateTopic + "] : [ON]");
    Serial.println("MQTT discovery signal config: [" + mqttDiscoSignalConfigTopic + "] : [" + mqttDiscoSignalConfigPayload + "]");
    Serial.println("MQTT discovery signal state: [" + mqttDiscoSignalStateTopic + "] : " + WiFi.RSSI());
    Serial.println("MQTT discovery uptime config: [" + mqttDiscoUptimeConfigTopic + "] : [" + mqttDiscoUptimeConfigPayload + "]");
    Serial.println("MQTT discovery uptime state: [" + mqttDiscoUptimeStateTopic + "] : " + uptimeTimer);
    mqttClient.publish(mqttDiscoUptimeConfigTopic.c_str(), mqttDiscoUptimeConfigPayload.c_str(), true);
    mqttClient.publish(mqttDiscoUptimeStateTopic.c_str(), uptimeTimer.c_str());
    mqttClient.publish(mqttDiscoBinaryConfigTopic.c_str(), mqttDiscoBinaryConfigPayload.c_str(), true);
    mqttClient.publish(mqttDiscoBinaryStateTopic.c_str(), "ON");
    mqttClient.publish(mqttDiscoSignalConfigTopic.c_str(), mqttDiscoSignalConfigPayload.c_str(), true);
    mqttClient.publish(mqttDiscoSignalStateTopic.c_str(), signalStrength.c_str());

    Serial.println("MQTT connected");
    digitalWrite(LED_BUILTIN, LOW);
  }
  else
  {
    Serial.println("MQTT connection failed, rc=" + String(mqttClient.state()));
  }
}

////////////////////////////////////////////////////////////////////////////////////////////////////
// (mostly) boilerplate OTA setup from library examples
void setupOTA()
{
  // Start up OTA
  // ArduinoOTA.setPort(8266); // Port defaults to 8266
  ArduinoOTA.setHostname(mqttNode.c_str());
  ArduinoOTA.setPassword(otaPassword);

  ArduinoOTA.onStart([]() {
    Serial.println("ESP OTA:  update start");
  });
  ArduinoOTA.onEnd([]() {
    Serial.println("ESP OTA:  update complete");
  });
  ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
    //Serial.printf("Progress: %u%%\r", (progress / (total / 100)));
  });
  ArduinoOTA.onError([](ota_error_t error) {
    Serial.println("ESP OTA:  ERROR code " + String(error));
    if (error == OTA_AUTH_ERROR)
      Serial.println("ESP OTA:  ERROR - Auth Failed");
    else if (error == OTA_BEGIN_ERROR)
      Serial.println("ESP OTA:  ERROR - Begin Failed");
    else if (error == OTA_CONNECT_ERROR)
      Serial.println("ESP OTA:  ERROR - Connect Failed");
    else if (error == OTA_RECEIVE_ERROR)
      Serial.println("ESP OTA:  ERROR - Receive Failed");
    else if (error == OTA_END_ERROR)
      Serial.println("ESP OTA:  ERROR - End Failed");
  });
  ArduinoOTA.begin();
  Serial.println("ESP OTA:  Over the Air firmware update ready");
}

`

First, read this: How to ask a question

Second, post code in code tags (see How to ask a question).

Last, are you in the right forums? The garbled code you posted is Arduino, C++.

I am sorry, I tried to fix the code many time to no avail, I posted before and I know how to tag but it seems some characters in the code do not allow the code tags to work

Anyway I managed to get the two switches discovered by Home Assistant via the discovery publish message

But all I have now is the state_topic for the two switches, how can I link these two switches to two pins on D1 Mini Pro?

Cheers

The GPIO pins are assigned in your device yaml code. What you tried to post is Arduino C++ code and Home Assistant doesn’t speak C++.

Fixing the code in the post is easy. Edit your post then select the code and then click on the </> icon above.

Cool, I have fixed the code tag. Cheers

Yes I know it is C++, but it is only to create the firmware (bin file), after that it works fine with HA and all switches and sensors ar dicovered by HA

I just cannot link an MQTT topic to any of the pins so far

Cheers

OK, it’s starting to make sense.
But, I am baffled how Home Assistant discovered the switches. What do they look like in Developer Tools -> State?

You did define the pins here:

#define HornPin D4
#define HazardPin D5

But then you set them up as an output:

pinMode(HornPin, OUTPUT);
pinMode(HazardPin, OUTPUT);

So physically connecting a switch to those pins make no sense.

Also, you never use the HornPin or HazardPin anywhere in your code. ??? Just what do you want the switches to do?

Hi Steve

Thanks for your reply, I managed to do the whole thing, I will explain first the process then I will add some code to show others how it is done

The Idea
1- When my car approaches my home, about 30 meters away, it should register in my Wifi network, it uses D1 Mini Pro running on 5V in my car

2- Step 1 is the trigger for Home Assistant automation, the trigger should open the garage door

3- Due to my house terrain, I have to reverse into my garage

4- I also have laser sensors to detect any movement under the garage door and if so, it stops the garage door motor

5- In addition to the laser sensors, I have 2 magnetic sensors at the top and bottom of the garage door, the bottom sensor will tell me if the garage is partially open, and both sensors will tell me if the garage is fully opened

6- Step 4 above caused a serious issue, sometimes it sends a false laser signal and this is enough to stop the garage door motor, so the garage door may be halfway opened, and while I am reversing, I can hit the garage door with the car as I only look at the side mirrors and unfortunately the side mirrors only show me the bottom half of the garage door and it looks open but in reality, it can be half-opened

7- So I came up with 3 measures to completely make sure that I do not hit the garage door in such a situation

a- Add to the automation stopping the laser sensors during the door opening phase when my car arrives home and trigger the door, then after opening, I activate the sensors again

This solution is not good enough because the door may get stuck halfway without any interference from the laser sensors, like a fault for example, or motor failure

b- Add a smart water-proof light that I can see with my side mirrors while reversing, and the light will turn on only when the top magnetic sensor of the garage door is triggered, this means the door is fully opened.

This solution is also not good enough as I live in Australia and the sun here is intense so on a sunny day I can hardly see the light on even if it is on, I am also old with vision issues

c- Modify the D1 Mini Pro sketch to add to the binary sensor of the Wifi connection, the Uptime sensor of the Wifi connection, and the Signal sensor of the wifi connection, the following

i- a switch to control the horn of my car
ii a switch to control the hazard lights of my car

And here is the idea on how it should work with the last solution even though I kept the first 2 solutions in place, like three layers of safety

a- When I arrive home with my car and about 30 meters away, my car will connect to my garage wifi

b- The D1 mini will trigger the automation to open the garage door and will trigger the hazard lights telling me the door started to open, by this time I will be reversing the car into the garage

c- When the door reaches the highest point, the D1 min will stop the hazard lights and will buzz my car horn for 50ms, enough to give me an audible indication that the door is fully opened

And it seems all working great after trying to do it in 4 days

Here are some of the codes

// We'll create one binary_sensor device to track MQTT connectivity
const String mqttDiscoBinaryStateTopic = mqttDiscoveryPrefix + "/binary_sensor/" + mqttNode + "/state";
const String mqttDiscoBinaryConfigTopic = mqttDiscoveryPrefix + "/binary_sensor/" + mqttNode + "/config";
// And a sensor for WiFi signal strength
const String mqttDiscoSignalStateTopic = mqttDiscoveryPrefix + "/sensor/" + mqttNode + "-signal/state";
const String mqttDiscoSignalConfigTopic = mqttDiscoveryPrefix + "/sensor/" + mqttNode + "-signal/config";
// And a sensor for device uptime
const String mqttDiscoUptimeStateTopic = mqttDiscoveryPrefix + "/sensor/" + mqttNode + "-uptime/state";
const String mqttDiscoUptimeConfigTopic = mqttDiscoveryPrefix + "/sensor/" + mqttNode + "-uptime/config";

// And switches for car horn and hazard
////const String mqttDiscoHornStateTopic = mqttDiscoveryPrefix + "/switch/" + mqttNode + "-horn/state";
const String mqttDiscoHornCommandTopic = mqttDiscoveryPrefix + "/switch/" + mqttNode + "-horn/set";
const String mqttDiscoHornConfigTopic = mqttDiscoveryPrefix + "/switch/" + mqttNode + "-horn/config";

//const String mqttDiscoHazardStateTopic = mqttDiscoveryPrefix + "/switch/" + mqttNode + "-hazard/state";
const String mqttDiscoHazardCommandTopic = mqttDiscoveryPrefix + "/switch/" + mqttNode + "-hazard/set";
const String mqttDiscoHazardConfigTopic = mqttDiscoveryPrefix + "/switch/" + mqttNode + "-hazard/config";

Preparing the Payload for MQTT auto-discovery on Home Assistant

// The strings below will spill over the PubSubClient_MAX_PACKET_SIZE 128
// You'll need to manually set MQTT_MAX_PACKET_SIZE in PubSubClient.h to 512
const String mqttDiscoBinaryConfigPayload = "{\"unique_id\": \"mazda_wf_presence\", \"name\": \"" + mqttNode + "\", \"device_class\": \"connectivity\", \"state_topic\": \"" + mqttDiscoBinaryStateTopic + "\"}";
const String mqttDiscoSignalConfigPayload = "{\"unique_id\": \"mazda_wf_signal\", \"name\": \"" + mqttNode + "-signal\", \"state_topic\": \"" + mqttDiscoSignalStateTopic + "\", \"unit_of_measurement\": \"dBm\", \"value_template\": \"{{ value }}\"}";
const String mqttDiscoUptimeConfigPayload = "{\"unique_id\": \"mazda_wf_uptime\", \"name\": \"" + mqttNode + "-uptime\", \"state_topic\": \"" + mqttDiscoUptimeStateTopic + "\", \"unit_of_measurement\": \"msec\", \"value_template\": \"{{ value }}\"}";

const String mqttDiscoHornConfigPayload = "{\"unique_id\": \"mazda_horn_switch\", \"name\": \"" + mqttNode + "-horn\", \"command_topic\": \"" + mqttDiscoHornCommandTopic + "\", \"payload_on\": \"on\", \"payload_off\": \"off\"}";
const String mqttDiscoHazardConfigPayload = "{\"unique_id\": \"mazda_hazard_switch\", \"name\": \"" + mqttNode + "-hazard\", \"command_topic\": \"" + mqttDiscoHazardCommandTopic + "\", \"payload_on\": \"on\", \"payload_off\": \"off\"}";

Publishing and subscribing to the 2 new switches in the sketch Setup() part

 mqttClient.subscribe(mqttDiscoHornCommandTopic.c_str());
 mqttClient.subscribe(mqttDiscoHazardCommandTopic.c_str());

  mqttClient.publish(mqttDiscoHornCommandTopic.c_str(), "off");
  mqttClient.publish(mqttDiscoHazardCommandTopic.c_str(), "off");  

Publishing in loop() section 2 switches and 2 sensors

if (mqttClient.connected() && ((millis() - reportTimer) >= reportInterval))
  {    
    String signalStrength = String(WiFi.RSSI());
    String uptimeTimer = String(millis());
    
    int hornState = digitalRead(HornPin);
    int hazardState = digitalRead(HazardPin);
    
    mqttClient.publish(mqttDiscoSignalStateTopic.c_str(), signalStrength.c_str());
    mqttClient.publish(mqttDiscoUptimeStateTopic.c_str(), uptimeTimer.c_str());
    mqttClient.publish(mqttDiscoHornCommandTopic.c_str(), hornState == HIGH ? "on" : "off");
    mqttClient.publish(mqttDiscoHazardCommandTopic.c_str(), hazardState == HIGH ? "on" : "off");
    reportTimer = millis();
  }

  // OTA loop
  if (otaPassword[0])
  {
    ArduinoOTA.handle();
  }
}

And finally, the MQTT callback to check MQTT messages

void mqtt_callback(char *topic, byte *payload, unsigned int payloadLength)
{
  // Convert payload to string
  payload[payloadLength] = '\0';
  String message = String((char*)payload);
 
  // Check which switch triggered the callback
  if (strcmp(topic, mqttDiscoHornCommandTopic.c_str()) == 0) {
    // Switch 1 callback
    if (message == "on") {
      digitalWrite(HornPin, HIGH);
      delay(50); 
      digitalWrite(HornPin, LOW);    

    } else if (message == "off") {
      digitalWrite(HornPin, LOW);
    }
  } else if (strcmp(topic, mqttDiscoHazardCommandTopic.c_str()) == 0) {
    // Switch 2 callback
    if (message == "on") {
      digitalWrite(HazardPin, HIGH);
    } else if (message == "off") {
      digitalWrite(HazardPin, LOW);
    }  
  }
}

I will welcome all feedback if any of the experts see any room for enhancement

Cheers

Hi Steve

That is exactly what I need, I need 2 pins on the microcontroller to control 2 relays on a relay module, one for the hazard light and one for the horn, however, I ended up with an issue with the D1 Mini, by design, it sets the pins to HIGH during boot which takes about 3 seconds, this means the horn will go off for 3 seconds whenever I start the car or whenever the D1 Mini boots, so I have to convert the code for ESP32 module which does not have this issue during boot, it seems all working fine but I just arranged for someone to swap the ESP32 internal antenna to an external antenna as my vision issues will not help me do that, I cannot even see the resistor and I even tried a telescope but I ended up damaging one ESP32 board, glad I have spares.I will update the post when all is done and tested well

Cheers

I am still baffled how you are using an Arduino sketch in ESPHome.

Also, are you using a D1 Mini or an ESP32? The D1 Mini is an ESP8266.

And, you’re driving?

I think you are overthinking the problem and making the solution far more complex than necessary.

First. Only some of the GPIO pins are high on boot. Here is a summary of which pins you can use.

Second. If I were designing this, it would all be in ESPHome. I do have some devices running Arduino code and the only “connection” to Home Assistant or ESPHome is over MQTT. And even those are going to be moved to ESPHome as soon as I can figure out how to control 14-segment LED displays from ESPHome.

Here is how I would do it.
There would be an ESP in the garage to control the motor and interior lights.
The ESP in the car would connect and the ESP in the garage would detect the connection and start the door open.
The ESP in the car would check the door status periodically and when it’s open, alert the driver that it’s OK to move.

You could add other sensors to the garage ESP to flag an unsafe condition which the car ESP could detect (periodically check for the safe state).