├── ESP32IOTSensor_RevE.ino └── Schematic_ESP32_CustomSensor.pdf /ESP32IOTSensor_RevE.ino: -------------------------------------------------------------------------------- 1 | /************************************************************************************************************************************************** 2 | * File name : ESP32IOTSensor_RevE.c 3 | * Compiler : 4 | * Autor : VIGASAN 5 | * Created : 24/02/2023 6 | * Modified : 7 | * Last modified : 8 | * 9 | * 10 | * Description : 11 | * 12 | * Other info : 13 | **************************************************************************************************************************************************/ 14 | 15 | 16 | /*-----------------------------------------------------------------------------------------------------------------------------------------------*/ 17 | /*------------------------------------Include Files----------------------------------------------------------------------------------------------*/ 18 | /*-----------------------------------------------------------------------------------------------------------------------------------------------*/ 19 | #include 20 | #include 21 | #include 22 | #include "Wire.h" 23 | 24 | 25 | /*-----------------------------------------------------------------------------------------------------------------------------------------------*/ 26 | /*------------------------------------Local definitions------------------------------------------------------------------------------------------*/ 27 | /*-----------------------------------------------------------------------------------------------------------------------------------------------*/ 28 | #define TMP102_I2C_ADDRESS 72 29 | #define I2C_SDA 23 30 | #define I2C_SCL 22 31 | 32 | 33 | /*-----------------------------------------------------------------------------------------------------------------------------------------------*/ 34 | /*------------------------------------I/O Definitions--------------------------------------------------------------------------------------------*/ 35 | /*-----------------------------------------------------------------------------------------------------------------------------------------------*/ 36 | const int KEEP_ON = 19; 37 | const int IN_DETECT_NO = 5; 38 | const int IN_DETECT_NC = 2; 39 | const int INT_DRV_TPL5111 = 16; 40 | const int OUT_DONE = 4; 41 | const int STATUS_LED = 25; 42 | 43 | /*-----------------------------------------------------------------------------------------------------------------------------------------------*/ 44 | /*------------------------------------ Configuration --------------------------------------------------------------------------------------------*/ 45 | /*-----------------------------------------------------------------------------------------------------------------------------------------------*/ 46 | const char* g_ssid = "your Wifi Name"; // Wifi Name 47 | const char* g_password = "Wifi Password"; // Wifi Password 48 | const char* g_mqtt_server = "192.168.1.25"; // MQTT Server IP, same of Home Assistant 49 | const char* g_mqttUser = "mqttUser"; // MQTT Server User Name 50 | const char* g_mqttPsw = "password"; // MQTT Server password 51 | int g_mqttPort = 1883; // MQTT Server Port 52 | 53 | // Variables used for MQTT Discovery 54 | const char* g_deviceModel = "ESP32IotSensor RevE"; // Hardware Model 55 | const char* g_swVersion = "1.0"; // Firmware Version 56 | const char* g_manufacturer = "Vigasan"; // Manufacturer Name 57 | String g_deviceName = "THC_Test"; // Device Name: YOU SEE THIS NAME ON HOME ASSISTANT DEVICES LIST 58 | String g_mqttStatusTopic = "esp32iotsensor/" + g_deviceName; // MQTT Topic 59 | 60 | 61 | /*-----------------------------------------------------------------------------------------------------------------------------------------------*/ 62 | /*------------------------------------Public variables-------------------------------------------------------------------------------------------*/ 63 | /*-----------------------------------------------------------------------------------------------------------------------------------------------*/ 64 | WiFiClient g_WiFiClient; 65 | PubSubClient g_mqttPubSub(g_WiFiClient); 66 | float g_BatteryVoltage = 0.0; 67 | int g_BatteryLevel = 0; 68 | unsigned long g_Time = 0; 69 | int g_samples = 0; 70 | int g_input_NO; 71 | int g_input_NC; 72 | String g_strInputStatus; 73 | int g_mqttCounterConn = 0; 74 | float g_Humidity = 0.0; 75 | float g_Temperature = 0.0; 76 | bool g_InitSystem = true; 77 | String g_UniqueId; 78 | bool g_WorkDone = false; 79 | byte g_CounterWork = 0; 80 | 81 | 82 | /*-----------------------------------------------------------------------------------------------------------------------------------------------*/ 83 | /*------------------------------------ SETUP ----------------------------------------------------------------------------------------------------*/ 84 | /*-----------------------------------------------------------------------------------------------------------------------------------------------*/ 85 | void setup() 86 | { 87 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 88 | // I/O Configuration 89 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 90 | analogSetWidth(11); 91 | analogSetAttenuation(ADC_11db); 92 | pinMode(IN_DETECT_NO, INPUT); 93 | pinMode(IN_DETECT_NC, INPUT); 94 | pinMode(INT_DRV_TPL5111, INPUT); 95 | pinMode(KEEP_ON, OUTPUT); 96 | pinMode(OUT_DONE, OUTPUT); 97 | pinMode(STATUS_LED, OUTPUT); 98 | 99 | digitalWrite(KEEP_ON, HIGH); 100 | digitalWrite(OUT_DONE, LOW); 101 | digitalWrite(STATUS_LED, HIGH); 102 | 103 | Serial.begin(115200); 104 | delay(500); 105 | 106 | Wire.begin(I2C_SDA, I2C_SCL); 107 | 108 | Serial.println(""); 109 | Serial.println(""); 110 | Serial.println("----------------------------------------------"); 111 | Serial.print("MODEL: "); 112 | Serial.println(g_deviceModel); 113 | Serial.print("DEVICE: "); 114 | Serial.println(g_deviceName); 115 | Serial.print("SW Rev: "); 116 | Serial.println(g_swVersion); 117 | Serial.println("----------------------------------------------"); 118 | 119 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 120 | // Configurazione Wifi 121 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 122 | setup_wifi(); 123 | 124 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 125 | // Configurazione MQTT 126 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 127 | g_mqttPubSub.setServer(g_mqtt_server, g_mqttPort); 128 | g_mqttPubSub.setCallback(MqttReceiverCallback); 129 | } 130 | 131 | /*-----------------------------------------------------------------------------------------------------------------------------------------------*/ 132 | /*------------------------------------ LOOP -----------------------------------------------------------------------------------------------------*/ 133 | /*-----------------------------------------------------------------------------------------------------------------------------------------------*/ 134 | void loop() 135 | { 136 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 137 | // Connessione MQTT 138 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 139 | if(WiFi.status() == WL_CONNECTED) 140 | { 141 | if(!g_mqttPubSub.connected()) 142 | MqttReconnect(); 143 | else 144 | g_mqttPubSub.loop(); 145 | } 146 | 147 | if(g_InitSystem) 148 | { 149 | delay(100); 150 | g_InitSystem = false; 151 | Serial.println("INIT SYSTEM..."); 152 | MqttHomeAssistantDiscovery(); 153 | } 154 | 155 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 156 | // Reads Temperature and Inputs (Door Contact) 157 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 158 | if(millis() > g_Time + 500) // Every 500 [msec] 159 | { 160 | g_Time = millis(); 161 | 162 | g_samples++; 163 | g_BatteryVoltage += ((analogRead(35) * 0.9) / 284.0) + 0.381; // Reads Battery Voltage with ADC 164 | 165 | if(g_samples == 4) // Average on 4 samples 166 | { 167 | g_BatteryVoltage = g_BatteryVoltage / g_samples; // Battery Volt 168 | g_BatteryLevel = 100 * (g_BatteryVoltage - 3.2) / (4.0 - 3.2); // Converts Battery Volt in Battery Level [%] 169 | g_samples = 0; 170 | 171 | if(g_BatteryLevel > 100) 172 | g_BatteryLevel = 100; 173 | else if(g_BatteryLevel < 0) 174 | g_BatteryLevel = 0; 175 | 176 | Serial.print("Battery Voltage: "); 177 | Serial.print(g_BatteryVoltage); 178 | Serial.println(" V"); 179 | 180 | Serial.print("Battery Level: "); 181 | Serial.print(g_BatteryLevel); 182 | Serial.println(" %"); 183 | 184 | //////////////////////////////////////////////////////////////// 185 | // DIGITAL INPUTS 186 | //////////////////////////////////////////////////////////////// 187 | g_input_NO = digitalRead(IN_DETECT_NO); 188 | g_input_NC = digitalRead(IN_DETECT_NC); 189 | 190 | if(g_input_NO == 0 && g_input_NC > 0) 191 | { 192 | Serial.println("OPEN!!!"); 193 | g_strInputStatus = "ON"; 194 | g_WorkDone = true; 195 | } else if(g_input_NO > 0 && g_input_NC == 0) 196 | { 197 | Serial.println("CLOSE!!!"); 198 | g_strInputStatus = "OFF"; 199 | g_WorkDone = true; 200 | } else 201 | { 202 | Serial.println("Undefined!!!"); 203 | if(g_CounterWork++ > 2) 204 | g_WorkDone = true; 205 | } 206 | 207 | Serial.print("INPUT_NO: "); 208 | Serial.println(g_input_NO); 209 | Serial.print("INPUT_NC: "); 210 | Serial.println(g_input_NC); 211 | 212 | //////////////////////////////////////////////////////////////// 213 | // TEMPERATURE 214 | //////////////////////////////////////////////////////////////// 215 | g_Temperature = TMP102_GetTemperature(); 216 | 217 | Serial.print("Temperature: "); 218 | Serial.print(g_Temperature); 219 | Serial.println(" °C"); 220 | 221 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 222 | // SEND MQTT DATA 223 | ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 224 | if(g_WorkDone == true) 225 | 226 | { 227 | StaticJsonDocument<200> payload; 228 | payload["batt"] = g_BatteryLevel; 229 | payload["volt"] = Round2(g_BatteryVoltage); 230 | payload["inputstatus"] = g_strInputStatus; 231 | payload["temp"] = Round(g_Temperature); 232 | 233 | String strPayload; 234 | serializeJson(payload, strPayload); 235 | 236 | if(g_mqttPubSub.connected()) 237 | { 238 | g_mqttPubSub.publish(g_mqttStatusTopic.c_str(), strPayload.c_str()); 239 | Serial.println("MQTT: Send Data!!!"); 240 | } 241 | 242 | delay(150); 243 | // SHUTDOWN 244 | Serial.println("Shutdown"); 245 | Serial.flush(); 246 | digitalWrite(OUT_DONE, LOW); 247 | delay(100); 248 | digitalWrite(OUT_DONE, HIGH); 249 | digitalWrite(KEEP_ON, LOW); 250 | delay(100); 251 | Serial.println(" "); 252 | Serial.println("This will never be printed"); 253 | } 254 | Serial.println(" "); 255 | Serial.println(" "); 256 | Serial.println(" "); 257 | Serial.println(" "); 258 | g_BatteryVoltage = 0.0; 259 | g_input_NO = 0; 260 | g_input_NC = 0; 261 | } 262 | } 263 | } 264 | 265 | 266 | /*-----------------------------------------------------------------------------------------------------------------------------------------------*/ 267 | /*------------------------------------ Public Functions -----------------------------------------------------------------------------------------*/ 268 | /*-----------------------------------------------------------------------------------------------------------------------------------------------*/ 269 | void setup_wifi() 270 | { 271 | int counter = 0; 272 | byte mac[6]; 273 | delay(10); 274 | // We start by connecting to a WiFi network 275 | Serial.print("Connecting to "); 276 | Serial.println(g_ssid); 277 | 278 | WiFi.begin(g_ssid, g_password); 279 | 280 | WiFi.macAddress(mac); 281 | g_UniqueId = String(mac[0],HEX) +String(mac[1],HEX) +String(mac[2],HEX) +String(mac[3],HEX) + String(mac[4],HEX) + String(mac[5],HEX); 282 | 283 | Serial.print("Unique ID: "); 284 | Serial.println(g_UniqueId); 285 | 286 | while(WiFi.status() != WL_CONNECTED && counter++ < 8) 287 | { 288 | delay(1000); 289 | Serial.print("."); 290 | } 291 | Serial.println(""); 292 | 293 | if(WiFi.status() == WL_CONNECTED) 294 | { 295 | Serial.println("WiFi connected"); 296 | Serial.print("IP address: "); 297 | Serial.println(WiFi.localIP()); 298 | } else 299 | { 300 | Serial.println("WiFi NOT connected!!!"); 301 | } 302 | } 303 | 304 | void MqttReconnect() 305 | { 306 | // Loop until we're reconnected 307 | while (!g_mqttPubSub.connected() && (g_mqttCounterConn++ < 4)) 308 | { 309 | Serial.print("Attempting MQTT connection..."); 310 | // Attempt to connect 311 | if (g_mqttPubSub.connect(g_deviceName.c_str(), g_mqttUser, g_mqttPsw)) 312 | { 313 | Serial.println("connected"); 314 | // Subscribe 315 | g_mqttPubSub.subscribe("homeassistant/status"); 316 | delay(100); 317 | } else 318 | { 319 | Serial.print("failed, rc="); 320 | Serial.print(g_mqttPubSub.state()); 321 | Serial.println(" try again in 1 seconds"); 322 | delay(1000); 323 | } 324 | } 325 | g_mqttCounterConn = 0; 326 | } 327 | 328 | void MqttHomeAssistantDiscovery() 329 | { 330 | String discoveryTopic; 331 | String payload; 332 | String strPayload; 333 | if(g_mqttPubSub.connected()) 334 | { 335 | Serial.println("SEND HOME ASSISTANT DISCOVERY!!!"); 336 | StaticJsonDocument<600> payload; 337 | JsonObject device; 338 | JsonArray identifiers; 339 | 340 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 341 | // Battery Level 342 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 343 | discoveryTopic = "homeassistant/sensor/esp32iotsensor/" + g_deviceName + "_batt" + "/config"; 344 | 345 | payload["name"] = g_deviceName + ".batt"; 346 | payload["uniq_id"] = g_UniqueId + "_batt"; 347 | payload["stat_t"] = g_mqttStatusTopic; 348 | payload["dev_cla"] = "battery"; 349 | payload["val_tpl"] = "{{ value_json.batt | is_defined }}"; 350 | payload["unit_of_meas"] = "%"; 351 | device = payload.createNestedObject("device"); 352 | device["name"] = g_deviceName; 353 | device["model"] = g_deviceModel; 354 | device["sw_version"] = g_swVersion; 355 | device["manufacturer"] = "VLC"; 356 | identifiers = device.createNestedArray("identifiers"); 357 | identifiers.add(g_UniqueId); 358 | 359 | serializeJsonPretty(payload, Serial); 360 | Serial.println(" "); 361 | serializeJson(payload, strPayload); 362 | 363 | g_mqttPubSub.publish(discoveryTopic.c_str(), strPayload.c_str()); 364 | 365 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 366 | // Battery Voltage 367 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 368 | payload.clear(); 369 | device.clear(); 370 | identifiers.clear(); 371 | strPayload.clear(); 372 | 373 | discoveryTopic = "homeassistant/sensor/esp32iotsensor/" + g_deviceName + "_volt" + "/config"; 374 | 375 | payload["name"] = g_deviceName + ".volt"; 376 | payload["uniq_id"] = g_UniqueId + "_volt"; 377 | payload["stat_t"] = g_mqttStatusTopic; 378 | payload["dev_cla"] = "voltage"; 379 | payload["val_tpl"] = "{{ value_json.volt | is_defined }}"; 380 | payload["unit_of_meas"] = "V"; 381 | device = payload.createNestedObject("device"); 382 | device["name"] = g_deviceName; 383 | device["model"] = g_deviceModel; 384 | device["sw_version"] = g_swVersion; 385 | device["manufacturer"] = "VLC"; 386 | identifiers = device.createNestedArray("identifiers"); 387 | identifiers.add(g_UniqueId); 388 | 389 | serializeJsonPretty(payload, Serial); 390 | Serial.println(" "); 391 | serializeJson(payload, strPayload); 392 | 393 | g_mqttPubSub.publish(discoveryTopic.c_str(), strPayload.c_str()); 394 | 395 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 396 | // Temperature 397 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 398 | payload.clear(); 399 | device.clear(); 400 | identifiers.clear(); 401 | strPayload.clear(); 402 | 403 | discoveryTopic = "homeassistant/sensor/esp32iotsensor/" + g_deviceName + "_temp" + "/config"; 404 | 405 | payload["name"] = g_deviceName + ".temp"; 406 | payload["uniq_id"] = g_UniqueId + "_temp"; 407 | payload["stat_t"] = g_mqttStatusTopic; 408 | payload["dev_cla"] = "temperature"; 409 | payload["val_tpl"] = "{{ value_json.temp | is_defined }}"; 410 | payload["unit_of_meas"] = "°C"; 411 | device = payload.createNestedObject("device"); 412 | device["name"] = g_deviceName; 413 | device["model"] = g_deviceModel; 414 | device["sw_version"] = g_swVersion; 415 | device["manufacturer"] = "VLC"; 416 | identifiers = device.createNestedArray("identifiers"); 417 | identifiers.add(g_UniqueId); 418 | 419 | serializeJsonPretty(payload, Serial); 420 | Serial.println(" "); 421 | serializeJson(payload, strPayload); 422 | 423 | g_mqttPubSub.publish(discoveryTopic.c_str(), strPayload.c_str()); 424 | 425 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 426 | // Binary Door 427 | /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 428 | payload.clear(); 429 | device.clear(); 430 | identifiers.clear(); 431 | strPayload.clear(); 432 | 433 | discoveryTopic = "homeassistant/binary_sensor/esp32iotsensor/" + g_deviceName + "_door" + "/config"; 434 | 435 | payload["name"] = g_deviceName + ".door"; 436 | payload["uniq_id"] = g_UniqueId + "_door"; 437 | payload["stat_t"] = g_mqttStatusTopic; 438 | payload["dev_cla"] = "door"; 439 | payload["val_tpl"] = "{{ value_json.inputstatus | is_defined }}"; 440 | device = payload.createNestedObject("device"); 441 | device["name"] = g_deviceName; 442 | device["model"] = g_deviceModel; 443 | device["sw_version"] = g_swVersion; 444 | device["manufacturer"] = "VLC"; 445 | identifiers = device.createNestedArray("identifiers"); 446 | identifiers.add(g_UniqueId); 447 | 448 | serializeJsonPretty(payload, Serial); 449 | Serial.println(" "); 450 | serializeJson(payload, strPayload); 451 | 452 | g_mqttPubSub.publish(discoveryTopic.c_str(), strPayload.c_str()); 453 | } 454 | } 455 | 456 | void MqttReceiverCallback(char* topic, byte* inFrame, unsigned int length) 457 | { 458 | Serial.print("Message arrived on topic: "); 459 | Serial.print(topic); 460 | Serial.print(". Message: "); 461 | byte state = 0; 462 | String messageTemp; 463 | 464 | for (int i = 0; i < length; i++) 465 | { 466 | Serial.print((char)inFrame[i]); 467 | messageTemp += (char)inFrame[i]; 468 | } 469 | Serial.println(); 470 | 471 | if(String(topic) == String("homeassistant/status")) 472 | { 473 | if(messageTemp == "online") 474 | MqttHomeAssistantDiscovery(); 475 | } 476 | } 477 | 478 | /*************************************************************************************************************************************************/ 479 | //NAME: TMP102_GetTemperature 480 | //DESCRPTION: 481 | //INPUT: void 482 | //RETURN: float 483 | //NOTE: 484 | /*************************************************************************************************************************************************/ 485 | float TMP102_GetTemperature() 486 | { 487 | byte res; 488 | byte msb; 489 | byte lsb; 490 | int val; 491 | float tC = 1000; // temperature in Celsius 492 | 493 | res = Wire.requestFrom(TMP102_I2C_ADDRESS, 2); 494 | 495 | if (res == 2) 496 | { 497 | msb = Wire.read(); /* Whole degrees */ 498 | lsb = Wire.read(); /* Fractional degrees */ 499 | val = ((msb) << 4); /* MSB */ 500 | val |= (lsb >> 4); /* LSB */ 501 | 502 | tC = val * 0.0625; /* calculate temperature */ 503 | 504 | //Serial.print(tC); 505 | //Serial.println(" °C"); 506 | } else 507 | { 508 | Serial.println("TEMPERTURE READING ERROR"); 509 | } 510 | 511 | return tC; 512 | } 513 | 514 | float Round(float value) 515 | { 516 | return (int)(value * 10 + 0.5) / 10.0; 517 | } 518 | 519 | float Round2(float value) 520 | { 521 | return (int)(value * 100 + 0.5) / 100.0; 522 | } 523 | -------------------------------------------------------------------------------- /Schematic_ESP32_CustomSensor.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vigasan/ESP32CustomSensor/cbded571e580884f23883bda1a799c8b944ba2e5/Schematic_ESP32_CustomSensor.pdf --------------------------------------------------------------------------------