diff --git a/platformio.ini b/platformio.ini index d444d19..98dabd1 100644 --- a/platformio.ini +++ b/platformio.ini @@ -16,7 +16,7 @@ lib_deps_external = haimoz/SoftFilters@^0.1.0 marvinroger/AsyncMqttClient@^0.9.0 bblanchon/ArduinoJson@^6.17.3 - juerd/ESP-WiFiSettings@^3.7.2 + https://github.com/ESPresense/ESP-WiFiSettings.git h2zero/NimBLE-Arduino@^1.3.1 me-no-dev/AsyncTCP@^1.1.1 bbx10/DNSServer@^1.1.0 diff --git a/src/main.cpp b/src/main.cpp index c2f8284..414504d 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,7 +4,7 @@ bool sendTelemetry(int totalSeen = -1, int totalReported = -1, int totalAdverts { if (!online) { - if (sendOnline() && sendDiscoveryConnectivity() && sendDiscoveryMaxDistance()) + if (sendOnline() && sendDiscoveryConnectivity() && sendDiscoveryMaxDistance() && sendDiscoveryMotion()) { online = true; reconnectTries = 0; @@ -82,7 +82,8 @@ void connectToWifi() Display.connecting(); return 150; }; - WiFiSettings.onPortalWaitLoop = []() { + WiFiSettings.onPortalWaitLoop = []() + { if (getUptimeSeconds() > 600) ESP.restart(); }; @@ -101,6 +102,8 @@ void connectToWifi() publishRooms = WiFiSettings.checkbox("pub_rooms", true, "Send to rooms topic"); publishDevices = WiFiSettings.checkbox("pub_devices", true, "Send to devices topic"); discovery = WiFiSettings.checkbox("discovery", true, "Hass Discovery"); + pirPin = WiFiSettings.integer("pir_pin", 0, "PIR Motion Sensor pin (0 for disable)"); + radarPin = WiFiSettings.integer("radar_pin", 0, "Radar Motion pin (0 for disable)"); maxDistance = WiFiSettings.integer("max_dist", DEFAULT_MAX_DISTANCE, "Maximum distance to report (in meters)"); WiFiSettings.hostname = "espresense-" + room; @@ -128,6 +131,10 @@ void connectToWifi() Serial.print("Discovery: "); Serial.println(discovery ? "enabled" : "disabled"); Serial.printf("Max Distance: %d\n", maxDistance); + Serial.print("PIR Sensor: "); + Serial.println(pirPin ? "enabled" : "disabled"); + Serial.print("Radar Sensor: "); + Serial.println(radarPin ? "enabled" : "disabled"); localIp = WiFi.localIP().toString(); roomsTopic = CHANNEL + "/rooms/" + room; @@ -139,7 +146,7 @@ void connectToWifi() void onMqttConnect(bool sessionPresent) { xTimerStop(reconnectTimer, 0); - uint16_t packetIdSub = mqttClient.subscribe(subTopic.c_str(), 2); + mqttClient.subscribe(subTopic.c_str(), 2); Display.connected(true, true); } @@ -156,11 +163,15 @@ void onMqttMessage(char *topic, char *payload, AsyncMqttClientMessageProperties char new_payload[len + 1]; new_payload[len] = '\0'; strncpy(new_payload, payload, len); - String pay = String(new_payload); - Serial.printf("%s: %s\n", topic, new_payload); - maxDistance = pay.toInt(); - spurt("/max_dist", String(new_payload)); + + String top = String(topic); + String pay = String(new_payload); + if (top == roomsTopic + "/max_distance/set") + { + maxDistance = pay.toInt(); + spurt("/max_dist", pay); + } } void reconnect(TimerHandle_t xTimer) @@ -276,6 +287,8 @@ void setup() #endif spiffsInit(); connectToWifi(); + if (pirPin) pinMode(pirPin, INPUT); + if (radarPin) pinMode(radarPin, INPUT); #if NTP setClock(); #endif @@ -284,9 +297,56 @@ void setup() configureOTA(); } +void pirLoop() +{ + if (!pirPin) return; + int pirValue = digitalRead(pirPin); + + if (pirValue != lastPirValue) + { + if (pirValue == HIGH) + { + mqttClient.publish((roomsTopic + "/motion").c_str(), 0, 1, "on"); + Serial.println("PIR MOTION DETECTED!!!"); + } + else + { + mqttClient.publish((roomsTopic + "/motion").c_str(), 0, 1, "off"); + Serial.println("NO PIR MOTION DETECTED!!!"); + } + + lastPirValue = pirValue; + } +} + +void radarLoop() +{ + if (!radarPin) return; + int radarValue = digitalRead(radarPin); + + if (radarValue != lastRadarValue) + { + if (radarValue == HIGH) + { + mqttClient.publish((roomsTopic + "/motion").c_str(), 0, 1, "on"); + Serial.println("Radar MOTION DETECTED!!!"); + } + else + { + mqttClient.publish((roomsTopic + "/motion").c_str(), 0, 1, "off"); + Serial.println("NO Radar MOTION DETECTED!!!"); + } + + lastRadarValue = radarValue; + } +} + void loop() { ArduinoOTA.handle(); firmwareUpdate(); Display.update(); + pirLoop(); + radarLoop(); + WiFiSettings.httpLoop(); } diff --git a/src/main.h b/src/main.h index b773b09..853c851 100644 --- a/src/main.h +++ b/src/main.h @@ -46,6 +46,11 @@ bool publishRooms; bool publishDevices; bool discovery; int maxDistance; +int pirPin; +int radarPin; + +int lastPirValue = -1; +int lastRadarValue = -1; BleFingerprintCollection fingerprints(MAX_MAC_ADDRESSES); @@ -113,36 +118,40 @@ void setClock() void configureOTA() { ArduinoOTA - .onStart([]() { - Serial.println("OTA Start"); - updateInProgress = true; - fingerprints.setDisable(updateInProgress); - }) - .onEnd([]() { - updateInProgress = false; - fingerprints.setDisable(updateInProgress); - Display.updateEnd(); - Serial.println("\n\rEnd"); - }) - .onProgress([](unsigned int progress, unsigned int total) { - byte percent = (progress / (total / 100)); - Serial.printf("Progress: %u\r\n", percent); - Display.updateProgress(progress); - }) - .onError([](ota_error_t error) { - Serial.printf("Error[%u]: ", error); - if (error == OTA_AUTH_ERROR) - Serial.println("Auth Failed"); - else if (error == OTA_BEGIN_ERROR) - Serial.println("Begin Failed"); - else if (error == OTA_CONNECT_ERROR) - Serial.println("Connect Failed"); - else if (error == OTA_RECEIVE_ERROR) - Serial.println("Receive Failed"); - else if (error == OTA_END_ERROR) - Serial.println("End Failed"); - updateInProgress = false; - }); + .onStart([]() + { + Serial.println("OTA Start"); + updateInProgress = true; + fingerprints.setDisable(updateInProgress); + }) + .onEnd([]() + { + updateInProgress = false; + fingerprints.setDisable(updateInProgress); + Display.updateEnd(); + Serial.println("\n\rEnd"); + }) + .onProgress([](unsigned int progress, unsigned int total) + { + byte percent = (progress / (total / 100)); + Serial.printf("Progress: %u\r\n", percent); + Display.updateProgress(progress); + }) + .onError([](ota_error_t error) + { + Serial.printf("Error[%u]: ", error); + if (error == OTA_AUTH_ERROR) + Serial.println("Auth Failed"); + else if (error == OTA_BEGIN_ERROR) + Serial.println("Begin Failed"); + else if (error == OTA_CONNECT_ERROR) + Serial.println("Connect Failed"); + else if (error == OTA_RECEIVE_ERROR) + Serial.println("Receive Failed"); + else if (error == OTA_END_ERROR) + Serial.println("End Failed"); + updateInProgress = false; + }); ArduinoOTA.setHostname(WiFi.getHostname()); ArduinoOTA.setPort(3232); ArduinoOTA.begin(); @@ -289,6 +298,35 @@ bool sendDiscoveryConnectivity() return false; } +bool sendDiscoveryMotion() +{ + if (!discovery) return true; + if (!pirPin && !radarPin) return true; + + String discoveryTopic = "homeassistant/binary_sensor/espresense_" + room + "/motion/config"; + + DynamicJsonDocument doc(1200); + char buffer[1200]; + + doc["~"] = roomsTopic; + doc["name"] = "ESPresense " + room + " Motion"; + doc["unique_id"] = WiFi.macAddress() + "_motion"; + doc["availability_topic"] = "~/status"; + doc["stat_t"] = "~/motion"; + doc["dev_cla"] = "motion"; + + commonDiscovery(&doc); + serializeJson(doc, buffer); + + for (int i = 0; i < 10; i++) + { + if (mqttClient.publish(discoveryTopic.c_str(), 0, true, buffer)) + return true; + delay(50); + } + return false; +} + bool sendDiscoveryMaxDistance() { if (!discovery) return true;