/* ESP32 HTTP IoT Server Example for Wokwi.com
https://wokwi.com/arduino/projects/320964045035274834
To test, you need the Wokwi IoT Gateway, as explained here:
https://docs.wokwi.com/guides/esp32-wifi#the-private-gateway
Then start the simulation, and open http://localhost:9080
in another browser tab.
Note that the IoT Gateway requires a Wokwi Club subscription.
To purchase a Wokwi Club subscription, go to https://wokwi.com/club
*/
#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h
#include <Bounce2.h>
#include <PubSubClient.h>
#define MQTT_SERVER "91.121.93.94"
#define WIFI_SSID "Wokwi-GUEST"
#define WIFI_PASSWORD ""
// Defining the WiFi channel speeds up the connection:
#define WIFI_CHANNEL 5
//topic to subscribe to for the temperature
WebServer server(80);
//LED pin for light
const int lightPin = 26;
//button on ESP8266 GPIO0
const int buttonPin = 27;
//topic to subscribe to the light
const char* lightTopic = "/house/light1";
//topic to publish to confirm that the light has been turned on for the python script to log
const char* lightConfirmTopic = "/house/light1confirm";
//create an instance of the bounce class
Bounce myButton = Bounce();
static boolean isOn = false; //static var to keep track of the intended current boiler state
// Callback function header
void callback(char* topic, byte* payload, unsigned int length);
WiFiClient wifiClient;
PubSubClient client(MQTT_SERVER, 1883, callback, wifiClient);
void setup(void) {
Serial.begin(115200);
pinMode(buttonPin, INPUT);
myButton.attach(buttonPin);
myButton.interval(5);
pinMode(lightPin, OUTPUT);
digitalWrite(lightPin, LOW);
delay(100);
WiFi.begin(WIFI_SSID, WIFI_PASSWORD, WIFI_CHANNEL);
reconnect();
delay(2000);
}
void loop(void) {
server.handleClient();
delay(2);
//reconnect if connection is lost
if (!client.connected() && WiFi.status() == 3) {reconnect();}
//maintain MQTT connection
client.loop();
//monitor the button
checkButton();
//MUST delay to allow ESP8266 WIFI functions to run
delay(10);
}
//MQTT callback
void callback(char* topic, byte* payload, unsigned int length) {
//convert topic to string to make it easier to work with
//convert topic to string to make it easier to work with
String topicStr = topic;
payload[length] = 0;
String recv_payload = String(( char *) payload);
//Print out some debugging info
Serial.println("Callback update.");
Serial.print("Topic: ");
Serial.println(topicStr);
Serial.println(recv_payload);
if(topicStr.equals(lightTopic)){
if (recv_payload == "update"){
if (isOn == true)
{
client.publish(lightConfirmTopic, "On");
}
else
{
client.publish(lightConfirmTopic, "Off");
}
}
else
{
lightSwitchUpdate();
}
}
}
void checkButton(){
if(myButton.update() && myButton.read() == HIGH){ //update the button and check for HIGH or LOW state
Serial.println("button pressed");
lightSwitchUpdate();
}
}
void lightSwitchUpdate(){
//on false, the boiler is off so tell it to turn on and set the internal var to true
if(isOn == false){
digitalWrite(lightPin, HIGH);
client.publish(lightConfirmTopic, "On");
Serial.println("light on");
isOn = true;
}
//else (on true), the light is on so tell it to turn off and set the internal var to false
else {
digitalWrite(lightPin, LOW);
client.publish(lightConfirmTopic,"Off");
Serial.println("light on");
isOn = false;
}
}
void reconnect() {
//attempt to connect to the wifi if connection is lost
if(WiFi.status() != WL_CONNECTED){
//loop while we wait for connection
while (WiFi.status() != WL_CONNECTED) {
Serial.print("TRY");
delay(500);
Serial.print(".");
}
//debug printing
Serial.println(" Connected!");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
}
//make sure we are connected to WIFI before attemping to reconnect to MQTT
if(WiFi.status() == WL_CONNECTED){
// Loop until we're reconnected to the MQTT server
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Generate client name based on MAC address and last 8 bits of microsecond counter
String clientName;
clientName += "esp8266-";
uint8_t mac[6];
WiFi.macAddress(mac);
clientName += macToStr(mac);
//if connected, subscribe to the topic(s) we want to be notified about
if (client.connect((char*) clientName.c_str())) {
Serial.print("\tMTQQ Connected");
client.subscribe(lightTopic);
}
//otherwise print failed for debugging
else{Serial.println("\tFailed."); abort();}
}
}
}
//generate unique name from MAC addr
String macToStr(const uint8_t* mac){
String result;
for (int i = 0; i < 6; ++i) {
result += String(mac[i], 16);
if (i < 5){
result += ':';
}
}
return result;
}