// ------------------------------------------
/*
* # OTAD => D - daemon
* # SSDL => L - ledpannel
*/
// ------------------------------------------
/*
* Hardware{
* bmp280 : {sck:GPIO23, sdo:GPIO19, sdi:GPIO22, cd:GPIO18}
* red_led : GPIO13 | MQTT
* blue_led : GPIO12 | PRESSURE
* yellow_led : GPIO27 | WIFI
* orange_led : GPIO33 | MQTT_CONTROL
* ssd : {sda: GPIO5, scl: GPIO4} # default wire
* button : GPIO34 | MQTT_CONTROL
* }
*/
// ------------------------------------------
#include <Wire.h>
#include <Adafruit_BMP280.h>
#include <Adafruit_SSD1306.h>
#include <WiFi.h>
#include <PubSubClient.h>
#include <HardwareSerial.h>
#include <ArduinoOTA.h>
// ----------------- MBP280 -----------------
#define BMP_SCK (23)
#define BMP_SDO (19)
#define BMP_SDI (22)
#define BMP_CS (18)
#define BMP_READ_PERIOD (3000)
Adafruit_BMP280 BMP_SENSOR (BMP_CS, BMP_SDI, BMP_SDO, BMP_SCK);
// LINK: https://wokwi.com/projects/394841903979791361
// ----------------- INTERACTIVE ------------
#define PRESSURE_LED (12)
#define MQTT_CONTROL_LED (33)
#define MQTT_CONTROL_BUTTON (34)
// LINK: https://wokwi.com/projects/379069495242330113
// ----------------- OTAD -------------------
const char* OTAD_HOSTNAME = "ESP_OTAD";
const char* OTAD_PASSWORD = "ESP_OTAD_PASSWORD";
const char* XTASK_PressureReader = "PressureReader";
const char* XTASK_MQTTPublisher = "MQTTPublisher";
// LINK: https://wokwi.com/projects/416366796309357569
// ----------------- SSDL -------------------
#define SSDL_SCL (4)
#define SSDL_SDA (5)
#define SSDL_WIDTH (128)
#define SSDL_HEIGHT (64)
TwoWire SSDL_WIRE = TwoWire(1);
Adafruit_SSD1306 SSDL (SSDL_WIDTH, SSDL_HEIGHT, &SSDL_WIRE, -1);
// LINK: https://wokwi.com/projects/350341364144144978
// ----------------- WIFI -------------------
const char* WIFI_SSID = "Wokwi-GUEST";
const char* WIFI_NATIVE_PASSWORD = "";
#define WIFI_LED (27)
WiFiClient WIFI_ESP_CLIENT;
// LINK: https://wokwi.com/projects/389054627163117569
// ----------------- MQTT -------------------
const char* MQTT_SERVER_HOST = "broker.hivemq.com";
const int MQTT_SERVER_PORT = 1883;
const char* MQTT_USER = "iot";
const char* MQTT_PASSWORD = "lab789";
const char* MQTT_TOPIC_CHANNEL = "iot/pressure";
const char* MQTT_CONTROL_CHANNEL = "iot/control";
#define MQTT_PUBLISH_PERIOD (10000)
#define MQTT_LED (13)
PubSubClient MQTT_ESP_CLIENT(WIFI_ESP_CLIENT);
// LINK: https://wokwi.com/projects/379986008338388993
// ----------------- TIMER ------------------
#define TICKRATE (1000)
float pressureValue;
unsigned long lastPressureRead = 0;
unsigned long lastMQTTPublish = 0;
int mqttControlButtonState = 0;
// ----------------- CONTROL ----------------
bool mqttPressureKey = true;
void mqtt_callback(char* topic, byte* payload, unsigned int length) {
payload[length] = '\0';
String message = String((char*)payload);
if (message == "ON") {
mqttPressureKey = true;
} else if (message == "OFF") {
mqttPressureKey = false;
}
}
// ------------------------------------------
void setup() {
Serial.begin(115200);
while (!Serial) delay(TICKRATE);
// BMP
if (!BMP_SENSOR.begin()) {
Serial.println(F("BMP is not implemented"));
while (1) delay(TICKRATE);
} else Serial.println(F("BMP implemented"));
BMP_SENSOR.setSampling(Adafruit_BMP280::MODE_NORMAL,
Adafruit_BMP280::SAMPLING_X2, // temp
Adafruit_BMP280::SAMPLING_X16, //press
Adafruit_BMP280::FILTER_X16,
Adafruit_BMP280::STANDBY_MS_500);
// INTERACTIVE
pinMode(PRESSURE_LED, OUTPUT);
pinMode(MQTT_CONTROL_LED, OUTPUT);
pinMode(MQTT_CONTROL_BUTTON, INPUT);
// WIFI
Serial.print("Connecting to Wi-Fi [");
Serial.print(WiFi.localIP());
Serial.print("]");
WiFi.begin(WIFI_SSID, WIFI_NATIVE_PASSWORD);
pinMode(WIFI_LED, OUTPUT);
while (WiFi.status() != WL_CONNECTED) {
delay(TICKRATE);
Serial.print(".");
}
Serial.println();
Serial.println("WiFi connected [SECURE].");
digitalWrite(WIFI_LED, HIGH);
// SSDL
SSDL_WIRE.begin(SSDL_SDA, SSDL_SCL);
if (!SSDL.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println(F("SSD1306 is not implemented"));
while (1) delay(TICKRATE);
} else Serial.println(F("SSDL implemented"));
// MQTT
MQTT_ESP_CLIENT.setServer(MQTT_SERVER_HOST, MQTT_SERVER_PORT);
pinMode(MQTT_LED, OUTPUT);
Serial.print("Connecting to MQTT");
while (!MQTT_ESP_CLIENT.connected()) {
if (MQTT_ESP_CLIENT.connect("MQTT_ESP_CLIENT", MQTT_USER, MQTT_PASSWORD)) { break; }
delay(TICKRATE);
Serial.print(".");
}
Serial.println();
Serial.println("MQTT connected [SECURE].");
digitalWrite(MQTT_LED, HIGH);
if (MQTT_ESP_CLIENT.subscribe(MQTT_CONTROL_CHANNEL)) {
Serial.println("[MQTT] Subscribed to control channel.");
}
MQTT_ESP_CLIENT.setCallback(mqtt_callback);
// THREADS
xTaskCreatePinnedToCore(taskReadPressure, XTASK_PressureReader, 4096, NULL, 1, NULL, 1);
xTaskCreatePinnedToCore(taskPublishMQTT, XTASK_MQTTPublisher, 4096, NULL, 1, NULL, 1);
// OTA
ArduinoOTA.setHostname(OTAD_HOSTNAME);
ArduinoOTA.setPassword(OTAD_PASSWORD);
ArduinoOTA.begin();
Serial.println("OTA ready");
}
// ------------------------------------------
void loop() {
unsigned long currentMillis = millis();
mqttControlButtonState = digitalRead(MQTT_CONTROL_BUTTON);
digitalWrite(MQTT_CONTROL_LED, (mqttPressureKey ? HIGH:LOW));
digitalWrite(PRESSURE_LED, (mqttPressureKey && pressureValue<1000 ? HIGH:LOW));
if (mqttControlButtonState == HIGH) {
Serial.println("BUTTON PRESSED");
MQTT_ESP_CLIENT.publish(MQTT_CONTROL_CHANNEL, mqttPressureKey?"OFF":"ON");
}
MQTT_ESP_CLIENT.loop();
ArduinoOTA.handle();
delay(TICKRATE);
}
// ------------------------------------------
void taskReadPressure(void *pvParameters) {
while (true) {
pressureValue = BMP_SENSOR.readPressure() / 100.0;
char buffer[32];
snprintf(buffer, sizeof(buffer), "Pressure: %.1f hPa", pressureValue);
Serial.println(buffer);
SSDL.clearDisplay();
SSDL.setTextSize(1);
SSDL.setTextColor(SSD1306_WHITE);
SSDL.setCursor(0, 0);
SSDL.println(F(buffer));
SSDL.display();
digitalWrite(PRESSURE_LED, (mqttPressureKey && pressureValue < 1000 ? HIGH : LOW));
vTaskDelay(pdMS_TO_TICKS(BMP_READ_PERIOD));
}
}
// ------------------------------------------
void taskPublishMQTT(void *pvParameters) {
while (true) {
if (!MQTT_ESP_CLIENT.connected()) {
digitalWrite(MQTT_LED, LOW);
while (!MQTT_ESP_CLIENT.connected()) {
if (MQTT_ESP_CLIENT.connect("MQTT_ESP_CLIENT", MQTT_USER, MQTT_PASSWORD)) break;
Serial.print(".");
vTaskDelay(pdMS_TO_TICKS(1000));
}
Serial.println();
Serial.println("MQTT reconnected [SECURE].");
digitalWrite(MQTT_LED, HIGH);
MQTT_ESP_CLIENT.subscribe(MQTT_CONTROL_CHANNEL);
}
if (mqttPressureKey) {
char buffer[64];
snprintf(buffer, sizeof(buffer), "[MQTT] Pressure: %.1f hPa", pressureValue);
bool status = MQTT_ESP_CLIENT.publish(MQTT_TOPIC_CHANNEL, buffer);
Serial.print("PUSH ");
Serial.print(buffer);
Serial.println(status ? " ✓" : " ✗");
}
vTaskDelay(pdMS_TO_TICKS(MQTT_PUBLISH_PERIOD));
}
}MQTT
PRESSURE
WIFI
MQTT_CONTROL
MQTT_CONTROL