// ledb-pb-mqtt.ino
// Written by Wong SS - 1 Nov 2023 
// this is similar to https://wokwi.com/projects/379930552025347073
// Except BLINK_T is used to do LED manipulation

// IMPORTANT: Make a copy of this project in your own wokwi free account.
// In prj.h, change the MQTT_ROOT_TOPIC name
// so that it will not clash with others running the same program

// IMPORTANT: In prj.h, MUST set these values correctly:
// MQTT_IN = 1 if WiFi and MQTT used, 0 if all local
// WOKWI   = 1 to use WiFi simulator in WOKWI, 0 to use really ESP32 hw

// Files:
// test-dly-io-mqtt.ino  - setup() and loop() ...
// prj.h                 - hardware connections
// dly-in-out.h          - C++ classes SDELAYMS_T, SINPUT_T and SOUTPUT_T definition
// dly-in-out.cpp        - C++ classes implementations
// blink.h and blink.cpp - BLINK_T class defined and implemented
// wifi-mqtt.cpp         - wifi and mqtt functions
// ===========================================================================================
// What this program does:
// Red LED toggles at .3s intervals
// Green LED toggles at 0.5s intervals

// Both Red and Green LEDs blinking can be disable/enabled by PB1 & PB2
// or sending 'r' or 'g' to serial monitor

// Yellow LED always on for 200ms and off for 1800ms as system heartbeat

// This program is non-blocking even if WiFi & MQTT used and their connections fail.
// The WiFi connection, disconnections handling (reconnection) are all event driven, thus non-blocking
// However, an attempt to connect to MQTT server may take a little bit of time

// If MQTT_IN==1:
// Can also control the Red LED blinking enable/disable
// Use e.g. mqtt explorer (https://mqtt-explorer.com/) or mobile app to  
// connect to "broker.emqx.io"

// PUBLISH (replace xxxx with the root name you use in prj.h)
// "xxxx/ledblink" with values "toggleR" or "toggleG"
// to enable/disable  Red & GReen LED blinking. IMPORTANT: NOT double quotes!

// SUBSCRIBE topics that has values of "1" or "0" (sent by the system every 2s)
// "xxxx/ledy" - toggle "1" and "0" at 2s intervals indicating system alive
// "xxxx/ledr" - "1" means Red blinking is enabled, "0" disabled
// "xxxx/ledg" - "1" means Green blinking is enabled, "0" disabled

#include "prj.h" // defines MQTT_IN, WOKWI and MQTT_ROOT_TOPIC
#include "blink.h"
#include "dly-in-out.h" // C++ classes: SDELAYMS_T, SINPUT_T, SOUTPUT_T
// ===========================================================================================
BLINK_T blink_R(ledPinR,ledOnVal,300,300); // default initally enabled and on
BLINK_T blink_Y(ledPinY,ledOnVal,200,1800);
BLINK_T blink_G(ledPinG,ledOnVal,500,500);

#if (MQTT_IN)  // defined in prj.h
// Functions in mqtt.cpp
void wifiMQTTInit();
void chkMQTT();
bool mqttPublish(char topic[], char value[]);
bool MQTT_ok();

char MQTT_ledVal_on[]  = "1";
char MQTT_ledVal_off[] = "0";
char ledStatusY[] = MQTT_ROOT_TOPIC "/ledy";   // toggle 2 sec intervals indicating system alive
char ledStatusR[] = MQTT_ROOT_TOPIC "/ledr";   // blinking on or off
char ledStatusG[] = MQTT_ROOT_TOPIC "/ledg";

void ledMqttBlinkReport() {
  if (blink_R.isEnabled()) {
  // if (LEDR_blink_enabled_flg) {
    mqttPublish(ledStatusR,MQTT_ledVal_on);
  }
  else {
    mqttPublish(ledStatusR,MQTT_ledVal_off);
  }
  if (blink_G.isEnabled()) {
  // if (LEDG_blink_enabled_flg) {
    mqttPublish(ledStatusG,MQTT_ledVal_on);
  }
  else {
    mqttPublish(ledStatusG,MQTT_ledVal_off);
  }
}
#endif

void ledInit() {
  Serial.print("\nInitialize LEDs");
  blink_R.blinkEnable();
  blink_Y.blinkEnable();
  blink_G.blinkEnable();
#if (MQTT_IN) // defined in prj.h
  Serial.printf(
    "\nSubscribe topics to show LED blinking status. Value \"1\"=on, \"0\"=off"
    "\n%s\n%s",ledStatusR,ledStatusG);
  Serial.printf(
    "\nIf system alive, this topic toggle between 1 and 0 at 2s intervals"
    "\n%s",ledStatusY);
  Serial.print("\nThese topic status are sent when Yellow LED turned on, i.e. every 2s");
#endif
}
// ===========================================================================================
SINPUT_T pb1(PB1,INPUT,200,LOW); // pin, inputType, bounceDuration, PressedIsLOW
SINPUT_T pb2(PB2,INPUT,200,LOW);
// ------------------------------------
void chkPBs() {
  if (pb1.justPressed()) {
    blink_R.toggleEnable();
    Serial.print("\nPB1 enable/disable Red LED blinking");
  }
  if (pb2.justPressed()) {
    blink_G.toggleEnable();
    Serial.print("\nPB2 enable/disable Green LED blinking");
  }
}
// ------------------------------------
void setup() {
  Serial.begin(115200);
  delay(100);
  Serial.print("\nDemo:"
    "\nRed & Green LEDs blink enable/disable controlled by PB1 & PB2, or Serial 'r' or 'g' cmds"
    "\nYellow LED always pulse at 0.2s on and 1.8s off as system heartbeat");
#if (MQTT_IN)
  Serial.print("\n\nMQTT ...."
    "\nIMPORTANT: Make a copy of this project in your own wokwi free account."
    "\nIn prj.h, change the MQTT_ROOT_TOPIC name to be unique to you"
    "\nso that it will not clash with others running the same program");
  wifiMQTTInit();
#endif
  ledInit();
  Serial.print("\nEnd of setup()\n");
}
// ------------------------------------
void chkSerial() {
  if (Serial.available()) {
    switch (Serial.read()) {
      case 'r': case 'R':
        blink_R.toggleEnable();
        Serial.print("\nSerial 'r' or 'R' enable/disable Red LED blinking");
        break;
      case 'g': case 'G':
        blink_G.toggleEnable();
        Serial.print("\nSerial 'g' or 'G' enable/disable Green LED blinking");
        break;
    }
  }
}
// ------------------------------------
#if (MQTT_IN)  // defined in prj.h
// Send MQTT msgs on LED status
void mqtt_ledPub() {
  static SDELAYMS_T pd(1000);
  if (!pd.dlyExpiredRestart() || !MQTT_ok()) return; // every second report

  static bool toggle = false;
  char *valptr;
  Serial.print("S");
  toggle = !toggle;
  valptr = toggle? MQTT_ledVal_on: MQTT_ledVal_off;
  mqttPublish(ledStatusY,valptr); // publish Yellow

  if (blink_R.isEnabled()) {
    mqttPublish(ledStatusR,MQTT_ledVal_on);
  }
  else {
    mqttPublish(ledStatusR,MQTT_ledVal_off);
  }
  if (blink_G.isEnabled()) {
    mqttPublish(ledStatusG,MQTT_ledVal_on);
  }
  else {
    mqttPublish(ledStatusG,MQTT_ledVal_off);
  }
}
#endif
// ------------------------------------
void loop() {
  blink_R.doBlink();
  blink_Y.doBlink();
  blink_G.doBlink();
  chkPBs();
  chkSerial();
#if (MQTT_IN)
  chkMQTT();  // Must be called very regularly to service MQTT msgs
  mqtt_ledPub();
#endif
}
// ------------------------------------
Follow NP SoE IoT Kit PB-LED pins
LOW to on
Pressed LOW
RLED pin23
YLED pin19
GLED pin18
PB1 pin27
PB2 pin25