I wanted to know if a pin can be used as both an input and output. I am using an ESPCam with the following library, paired with some custom code to read an MQTT server and check the value of a sensor.The library includes a function to add a PIR sensor using pin 12. Instead of hard wiring any form of sensor I want to read the MQTT server for the current state of a hall effect sensor and pull pin 12 High (which should trigger a recording) if the sensor returns a 0.
The code has been set as a INPUT_PULLDOWN in the mjpeg2sd.cpp. Is it possible for me to programatically set that pin to high. I have created another file called checkDoor.cpp with the following code to do this.
#include <Arduino.h>
#include "myConfig.h"
WiFiClient espClient;
PubSubClient mqttclient(espClient);
String state = "0";
void callback(char *topic, byte *payload, unsigned int length)
{
Serial.print("Message arrived in topic: ");
Serial.println(topic);
Serial.print("Message:");
payload[length] = '\0';
state = String((char *)payload);
for (int i = 0; i < length; i++)
{
Serial.print((char)payload[i]);
}
Serial.println();
Serial.println("-----------------------");
Serial.println(state);
}
void setupmqtt()
{
mqttclient.setServer(mqttServer, mqttPort);
mqttclient.setCallback(callback);
while (!mqttclient.connected())
{
String client_id = "ESP32-client-";
client_id += String(WiFi.macAddress());
Serial.printf("The client %s connects to the public mqtt broker\n", client_id.c_str());
if (mqttclient.connect(client_id.c_str(), mqttUser, mqttPassword))
{
Serial.println("Public emqx mqtt broker connected");
}
else
{
Serial.print("failed with state ");
Serial.print(mqttclient.state());
delay(2000);
}
mqttclient.subscribe("esp/door");
pinMode(12, OUTPUT);
}
}
void reconnect()
{
while (!mqttclient.connected())
{
Serial.print("\nConnecting to ");
Serial.println(mqttServer);
if (mqttclient.connect("ESP32", mqttUser, mqttPassword))
{
Serial.print("\nConnected to ");
Serial.print(mqttServer);
mqttclient.subscribe("esp/cam");
}
else
{
Serial.print("\nTring to connect again ");
delay(5000);
}
}
}
void readmqtt()
{
if (!mqttclient.connected())
{
reconnect();
}
while (mqttclient.connected())
{
mqttclient.loop();
if (state == "Open")
{
digitalWrite(12, HIGH);
Serial.println("Door Open... Start Recording");
delay(10000);
}
if (state == "Closed")
{
digitalWrite(12, LOW);
Serial.println("Door Closed... Stop Recording");
}
}
}
I realise I am redefining pin 12 as an output here... I wasn't sure how to go about it but this doesn't do the trick. At least it doesn't trigger the PIR sensor which reads pin 12 to see if it's HIGH
Any help or advice would be greatly appreciated.
What is the original purpose of the IO-pin 12?
Is this IO-pin used to start recording?
If yes and you want to modify this to start recordning by something else you have to provide all code that is involved in reading IO-pin 12 and your code that has the modifcation for start/stop recording on a different condition.
The other solution would be to add an I2C-IO-expander like MCP23017 to get more IO-pins.
by default, pins are configured as INPUT since at startup it is unknown what device is connected to it and the pin can be damaged if that device driving the pin in on direction (e.g. HIGH) and the processor drives it in the opposite direction (e.g. LOW)
The code is in the linked github repo, below I've highlighted the specific references.
Specifically. The pin is set as INPUT_PULLDOWN here
bool prepRecording() {
// initialisation & prep for AVI capture
pinMode(4, OUTPUT);
digitalWrite(4, 0); // set pin 4 fully off as sd_mmc library still initialises pin 4 in 1 line mode
if (USE_PIR) pinMode(PIR_PIN, INPUT_PULLDOWN); // pulled high for active
if (USE_LAMP) pinMode(LAMP_PIN, OUTPUT);
readSemaphore = xSemaphoreCreateBinary();
playbackSemaphore = xSemaphoreCreateBinary();
aviMutex = xSemaphoreCreateMutex();
motionMutex = xSemaphoreCreateMutex();
camera_fb_t* fb = esp_camera_fb_get();
if (fb == NULL) LOG_WRN("failed to get camera frame");
else {
esp_camera_fb_return(fb);
fb = NULL;
}
This is in the following file of the repo
To simplify, I do need to be able to read this pin as well as control its state. The code anticipated this pin to be used with an IR sensor which is why it's registered as an input with the internal pulldown. I suppose the solution would be to change the pinMode to output since as you've suggested, outputs can also be read using digitalRead();?
Apologies. The pin is used in the code to trigger a recording. When the pin is set high it begins a recording and stops it once the pin is set low. The pin isn't connected to anything. Typing this out I'm beginning to realise this seems a silly task to essentially use a pin state as a variable. I suppose it seemed easier than writing new code as I don't fully understand the under workings of the library. I have found a "forceRecord" Variable. I'll give that a test and hopefully I can use that instead of trying to read and write to pin 12
This is the all deciding detail. As long as there is something physically connected to the IO-pin it would be dangerous to switch it to output-mode. Because as long as you don't know the connected devices resistance you are in danger of overloading the IO-pin with a too high current that would damage the microcontroller.
If it is is really true that really nothing is connected to the IO-pin changing it to output-mode and then do digitalWrite would have a chance to make it work.
As this requires to modify the library itself I suggest that you add a boolean variable that is set to true from your code to make the recording start. In this way as long as this boolean variable is set to false the code reacts in the same way as without this modification.
If the library itself offers a second way of start/stopping the recording use this way.