#define ESP_DRD_USE_LITTLEFS true #define DRD_TIMEOUT 10 #define DRD_ADDRESS 0 #define JSON_CONFIG_FILE "/config.json" #define TUBE_NAME "J305" #define TUBE_FACTOR 0.00812 #define SCREEN_WIDTH 128 #define SCREEN_HEIGHT 64 #define i2c_Address 0x3c #define OLED_RESET -1 #include #include #include #include #include #include #include #include "time.h" #include #include #include DoubleResetDetector* drd; WiFiClient espClient; // connection for MQTT WiFiClient espClient2; // connection fot HTTP Client PubSubClient client(espClient); Adafruit_SH1106G display = Adafruit_SH1106G(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); // Initialize LittleFS void initLittleFS() { if (!LittleFS.begin(true)) { Serial.println("An error has occurred while mounting LittleFS"); } Serial.println("LittleFS mounted successfully"); } char mqttServer[50] = ""; char mqttUser[50] = ""; char mqttPass[50] = ""; char gmcAccountID[50] = ""; char gmcDeviceID[50] = ""; char rmUser[50] = ""; char rmPass[50] = ""; bool shouldSaveConfig = false; char buf[10]; char buf2[10]; unsigned long time_now = 0; unsigned long time_now2 = 0; unsigned long mold = 0; unsigned long currentMillis = 0; unsigned long previousMillis_60s = 0; const long interval_60s = 60000; unsigned long previousMillis_10m = 0; const long interval_10m = 600000; const byte interruptPin = 13; volatile unsigned long GeigerCounts = 0; void ICACHE_RAM_ATTR handleInterrupt() { GeigerCounts++; } const char* ntpServer = "europe.pool.ntp.org"; const long gmtOffset_sec = 3600; // GMT +1 = 3600 const int daylightOffset_sec = 3600; String GMCMap_Request_payload = "http://www.GMCmap.com/log2.asp"; String GMCMap_Request = ""; String GMCMap_Data = ""; String GMCMap = "NONE"; struct tm timeinfo; void saveConfigFile() { Serial.println(F("Saving config")); StaticJsonDocument<512> json; json["mqttServer"] = mqttServer; json["mqttUser"] = mqttUser; json["mqttPass"] = mqttPass; json["gmcAccountID"] = gmcAccountID; json["gmcDeviceID"] = gmcDeviceID; json["rmUser"] = rmUser; json["rmPass"] = rmPass; File configFile = FileFS.open(JSON_CONFIG_FILE, "w"); if (!configFile) { Serial.println("failed to open config file for writing"); } serializeJsonPretty(json, Serial); if (serializeJson(json, configFile) == 0) { Serial.println(F("Failed to write to file")); } configFile.close(); } bool loadConfigFile() { //read configuration from FS json Serial.println("mounting FS..."); if (FileFS.begin(false) || FileFS.begin(true)) { Serial.println("mounted file system"); if (FileFS.exists(JSON_CONFIG_FILE)) { //file exists, reading and loading Serial.println("reading config file"); File configFile = FileFS.open(JSON_CONFIG_FILE, "r"); if (configFile) { Serial.println("opened config file"); StaticJsonDocument<512> json; DeserializationError error = deserializeJson(json, configFile); serializeJsonPretty(json, Serial); if (!error) { Serial.println("\nparsed json"); strcpy(mqttServer, json["mqttServer"]); strcpy(mqttUser, json["mqttUser"]); strcpy(mqttPass, json["mqttPass"]); strcpy(gmcAccountID, json["gmcAccountID"]); strcpy(gmcDeviceID, json["gmcDeviceID"]); strcpy(rmUser, json["rmUser"]); strcpy(rmPass, json["rmPass"]); return true; } else { Serial.println("failed to load json config"); } } } } else { Serial.println("failed to mount FS"); } //end read return false; } void saveConfigCallback() { Serial.println("Should save config"); shouldSaveConfig = true; } void reconnect() { // Loop until we're reconnected while (!client.connected()) { Serial.print("Attempting MQTT connection..."); // Attempt to connect if (client.connect("GeigerClient")) { Serial.println("connected"); } else { Serial.print("failed, rc="); Serial.print(client.state()); Serial.println(" try again in 5 seconds"); // Wait 5 seconds before retrying delay(5000); } } } void lcdPrint(String x) { display.clearDisplay(); display.setTextSize(1); display.setTextColor(SH110X_WHITE); display.setCursor(0, 10); display.println(x); display.display(); } void lcdUpdate() { display.clearDisplay(); display.setTextSize(1); display.setTextColor(SH110X_WHITE); display.setCursor(0, 0); display.println(printLocalTime()); display.println("uSv/h: " + String(buf2)); display.println("CPM: " + String(buf)); display.display(); } String printLocalTime() { //if(!getLocalTime(&timeinfo)){ // Serial.println("Failed to obtain time"); // return "Failed to obtain time"; //} char buffer[80]; //strftime(buffer, 80, "%H:%M:%S %d-%m-%Y ", &timeinfo); strftime(buffer, 80, "%H:%M <|> %d-%m-%Y ", &timeinfo); return String(buffer); } void radmonUpload(int cpm) { const char *cmdFormat = "http://radmon.org/radmon.php?function=submit&user=%s&password=%s&value=%d&unit=CPM"; char url[256]; HTTPClient http2; // create the request URL sprintf(url, cmdFormat, rmUser, rmPass, cpm); Serial.print("[HTTP] begin: "); Serial.println(url); if (http2.begin(espClient2, url)) { Serial.print("[HTTP] GET..."); // start connection and send HTTP header int httpCode = http2.GET(); // HTTP header has been sent and server response header has been handled Serial.printf(" code: %d\n", httpCode); // httpCode will be negative on error if (httpCode > 0) { // file found at server if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) { String payload = http2.getString(); Serial.println(payload); } } else { Serial.printf("[HTTP] GET failed, error: %s\n", http2.errorToString(httpCode).c_str()); } http2.end(); } } void setup() { // WiFi.mode(WIFI_STA); // explicitly set mode, esp defaults to STA+AP // it is a good practice to make sure your code sets wifi mode how you want it. Serial.begin(115200); pinMode( interruptPin, INPUT ); attachInterrupt(digitalPinToInterrupt(interruptPin), handleInterrupt, FALLING ); initLittleFS(); display.begin(i2c_Address, true); lcdPrint("Geiger Interace"); drd = new DoubleResetDetector(DRD_TIMEOUT, DRD_ADDRESS); bool forceConfig = false; if (drd->detectDoubleReset()) { Serial.println("Double Reset Detected"); forceConfig = true; } WiFiManager wm; wm.setSaveConfigCallback(saveConfigCallback); WiFiManagerParameter custom_mqttServer("mqttServer", "MQTT Server", mqttServer, 50); WiFiManagerParameter custom_mqttUser("mqttUser", "MQTT User", mqttUser, 50); WiFiManagerParameter custom_mqttPass("mqttPass", "MQTT Password", mqttPass, 50); WiFiManagerParameter custom_gmcAccountID("gmcAccountID", "GMC MAP Account ID", gmcAccountID, 50); WiFiManagerParameter custom_gmcDeviceID("gmcDeviceID", "GMC MAP Device ID", gmcDeviceID, 50); WiFiManagerParameter custom_rmUser("rmUser", "RadMon User", rmUser, 50); WiFiManagerParameter custom_rmPass("rmPass", "RadMon Password", rmPass, 50); wm.addParameter(&custom_mqttServer); wm.addParameter(&custom_mqttUser); wm.addParameter(&custom_mqttPass); wm.addParameter(&custom_gmcAccountID); wm.addParameter(&custom_gmcDeviceID); wm.addParameter(&custom_rmUser); wm.addParameter(&custom_rmPass); // wm.resetSettings(); bool res; res = wm.autoConnect(); if (!res) { Serial.println("Failed to connect"); // ESP.restart(); } else { Serial.println("connected...yeey :)"); if (forceConfig) { if (!wm.startConfigPortal()) { Serial.println("failed to connect and hit timeout"); delay(3000); ESP.restart(); delay(5000); } } } strcpy(mqttServer, custom_mqttServer.getValue()); strcpy(mqttUser, custom_mqttUser.getValue()); strcpy(mqttPass, custom_mqttPass.getValue()); strcpy(gmcAccountID, custom_gmcAccountID.getValue()); strcpy(gmcDeviceID, custom_gmcDeviceID.getValue()); strcpy(rmUser, custom_rmUser.getValue()); strcpy(rmPass, custom_rmPass.getValue()); Serial.println("The values in the file are: "); Serial.println("\tmqtt_server : " + String(mqttServer)); Serial.println("\tmqtt_user : " + String(mqttUser)); Serial.println("\tmqtt_pass : " + String(mqttPass)); Serial.println("\tgmc_AccountID : " + String(gmcAccountID)); Serial.println("\tgmc_DeviceID : " + String(gmcDeviceID)); Serial.println("\trm_User : " + String(rmUser)); Serial.println("\trm_Pass : " + String(rmPass)); if (shouldSaveConfig) { Serial.println("saving config"); saveConfigFile(); } loadConfigFile(); client.setServer(mqttServer, 1883); configTime(gmtOffset_sec, daylightOffset_sec, ntpServer); printLocalTime(); } void loop() { drd->loop(); // if MQTT server provided if (String(mqttServer) != "") { if (!client.connected()) { reconnect(); } if(millis() >= time_now + 5000){ time_now += 5000; client.publish("esp32/heartbeat", "PING"); } if (millis() >= mold + 60000) { ltoa(GeigerCounts, buf, 10); dtostrf(GeigerCounts*TUBE_FACTOR, -4, 2, buf2); client.publish("esp32/CPM", buf); client.publish("esp32/uSv", buf2); GeigerCounts = 0; mold += 60000; lcdUpdate(); } client.loop(); } getLocalTime(&timeinfo); if (timeinfo.tm_sec == 0){ lcdUpdate(); } // if GMC IDs provided if (String(gmcAccountID) != "") { currentMillis = millis(); if (currentMillis - previousMillis_10m >= interval_10m) { previousMillis_10m = currentMillis; Serial.print("[HTTP] begin...\n"); GMCMap_Request = GMCMap_Request_payload + "?AID=" + gmcAccountID + "&GID=" + gmcDeviceID + "&CPM=" + buf + "&ACPM=" + buf + "&uSV=" + buf2; Serial.println(GMCMap_Request); HTTPClient http; if (http.begin(espClient2, GMCMap_Request)) { // HTTP Serial.print("[HTTP] GET...\n"); int httpCode = http.GET(); if (httpCode > 0) { Serial.printf("[HTTP] GET... code: %d\n", httpCode); if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY) { String payload = http.getString(); Serial.println(payload); if (payload.indexOf("ERR0") > 0) GMCMap = "OK"; if (payload.indexOf("ERR1") > 0) GMCMap = "Error! User is not found"; if (payload.indexOf("ERR2") > 0) GMCMap = "Error! Geiger Counter is not found"; if (payload.indexOf("Warning") > 0) GMCMap = "Warning! The Geiger Counter location changed, please confirm the location"; Serial.println(GMCMap); } } else { Serial.printf("[HTTP] GET... failed, error: %s\n", http.errorToString(httpCode).c_str()); GMCMap = http.errorToString(httpCode).c_str(); } http.end(); } else { Serial.println("[HTTP] Unable to connect"); GMCMap = "Unable to connect"; } } } }