/* * ModularWeatherStation * * Copyright (C) 2021 Gergely Polonkai * Author: Gergely POLONKAI * * ModularWeatherStation is free software: you can redistribute it * and/or modify it under the terms of the GNU General Public License * as published by the Free Software Foundation, either version 3 of * the License, or (at your option) any later version. * * ModularWeatherStation is distributed in the hope that it will be * useful, but WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * As additional permission under GNU GPL version 3 section 7, you may * distribute non-source form of the Program without the copy of the * GNU GPL normally required by section 4, provided you inform the * receipents of GNU GPL by a written offer. * */ #include #include #include #include #include "config.h" #ifdef DHT_TYPE # include #endif // DHT_TYPE #if defined(HAVE_BH1750) || defined(HAVE_BMP180) # include #endif // defined(HAVE_BH1750) || defined(HAVE_BMP180) #ifdef HAVE_BH1750 # include #endif // HAVE_BH1750 #ifdef HAVE_BMP180 # include #endif // HAVE_BMP180 char *negotiated_hostname = NULL; bool hostname_verified = false; MDNSResponder::hMDNSService mdns_service = NULL; ESP8266WebServer server(80); unsigned long last_update = 0; #ifdef DHT_TYPE DHT dht(DHT_PIN, DHT_TYPE); float humidity = 0.0; #endif // DHT_TYPE #ifdef RAIN_PIN bool raining = false; #endif // RAIN_PIN #ifdef HAVE_BH1750 BH1750 light; float light_level = 0; #endif // HAVE_BH1750 #if defined(DHT_TYPE) || defined(HAVE_BMP180) float temperature = 0.0; #endif // defined(DHT_TYPE) || defined(HAVE_BMP180) #ifdef HAVE_BMP180 Adafruit_BMP085 BMP; uint32_t pressure = 0; #endif // HAVE_BMP180 static const char TEXT_PLAIN[] PROGMEM = "text/plain"; void reply_not_found() { server.send(404, FPSTR(TEXT_PLAIN), "Not Found"); } void send_metrics() { static const size_t temperature_size = 117; static const size_t humidity_size = 111; static const size_t rain_size = 86; static const size_t light_size = 72; static const size_t pressure_size = 82; size_t message_size = #if defined(DHT_TYPE) || defined(HAVE_BMP180) temperature_size + #endif // defined(DHT_TYPE) || defined(HAVE_BMP180) #ifdef DHT_TYPE humidity_size + #endif // DHT_TYPE #ifdef RAIN_PIN rain_size + #endif // RAIN_PIN #ifdef HAVE_BH1750 light_size + #endif // HAVE_BH1750 #ifdef HAVE_BMP180 pressure_size + #endif // HAVE_BMP180 1; char message[message_size]; snprintf(message, message_size, "" #if defined(DHT_TYPE) || defined(HAVE_BMP180) "# HELP temperature_celsius Temperature in degrees Celsius\n" "# TYPE temperature_celsius gauge\n" "temperature_celsius %.2f\n" #endif // defined(DHT_TYPE) || defined(HAVE_BMP180) #ifdef DHT_TYPE "# HELP relative_humidity Relative humidity, in percents\n" "# TYPE relative_humidity gauge\n" "relative_humidity %.2f\n" #endif // DHT_TYPE #ifdef RAIN_PIN "# HELP raining Boolean value checking if it is raining\n" "# TYPE raining gauge\n" "raining %d\n" #endif // RAIN_PIN #ifdef HAVE_BH1750 "# HELP light Ambient light, in lumens\n" "# TYPE light gauge\n" "light %.2f\n" #endif // HAVE_BH1750 #ifdef HAVE_BMP180 "# HELP pressure Atmospheric pressure, in Pa\n" "# TYPE pressure gauge\n" "pressure %d\n" #endif // HAVE_BMP180 #if defined(DHT_TYPE) || defined(HAVE_BMP180) , temperature #endif // defined(DHT_TYPE) || defined(HAVE_BMP180) #ifdef DHT_TYPE , humidity #endif // DHT_TYPE #ifdef RAIN_PIN , raining ? 1 : 0 #endif // RAIN_PIN #ifdef HAVE_BH1750 , light_level #endif // HAVE_BH1750 #ifdef HAVE_BMP180 , pressure #endif // HAVE_BMP180 ); server.send(200, "text/plain; version=0.0.4; charset=utf-8", message); } void stop() { while (1) { delay(1000); } } bool set_station_hostname(const char *hostname) { if (hostname) { WiFi.hostname(hostname); } return true; } void host_probe_result(String hostname, bool result) { if (result == true) { set_station_hostname(negotiated_hostname); if (!hostname_verified) { hostname_verified = true; if (!mdns_service) { mdns_service = MDNS.addService(0, "http", "tcp", 80); if (mdns_service) { MDNS.addServiceTxt(mdns_service, "port#", 80); } } } } else { if (MDNSResponder::indexDomain(negotiated_hostname, "-", 0)) { MDNS.setHostname(negotiated_hostname); } else { Serial.println("Failed to set mDNS hostname"); } } } void setup() { IPAddress address; Serial.begin(9600); WiFi.mode(WIFI_STA); WiFi.begin(WIFI_SSID, WIFI_PASS); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.println("Waiting for WiFi to connect..."); } address = WiFi.localIP(); Serial.print("WiFi Address: "); address.printTo(Serial); Serial.println(""); MDNS.setHostProbeResultCallback(host_probe_result); if ((!MDNSResponder::indexDomain(negotiated_hostname, 0, SYSTEM_NAME)) || (!MDNS.begin(negotiated_hostname))) { Serial.println("Error setting up mDNS!"); stop(); } server.on("/metrics", HTTP_GET, send_metrics); server.onNotFound(reply_not_found); server.begin(); // Initialize sensors #ifdef DHT_TYPE dht.begin(); #endif // DHT_TYPE #ifdef RAIN_PIN pinMode(RAIN_PIN, INPUT); #endif // RAIN_PIN #ifdef HAVE_BH1750 Wire.begin(I2C_SDA_PIN, I2C_SCL_PIN); if (!light.begin()) { Serial.println("Could not find the BH1750 sensor!"); stop(); } #endif // HAVE_BH1750 #ifdef HAVE_BMP180 if (!bmp.begin()) { Serial.println("Could not find the BMP180 sensor!"); stop(); } #endif // HAVE_BMP180 Serial.println("All set, starting the loop."); } void read_sensors() { // Turn on the LED to indicate that we’re working digitalWrite(LED_BUILTIN, LOW); #if defined(DHT_TYPE) temperature = dht.readTemperature(); humidity = dht.readHumidity(); #endif // DHT_TYPE #ifdef RAIN_PIN raining = (digitalRead(RAIN_PIN) == HIGH); #endif #ifdef HAVE_BH1750 light_level = light.readLightLevel(); #endif // HAVE_BH1750 #ifdef HAVE_BMP180 pressure = bmp.readPressure(); // If we have a DHT sensor, we already measured the temperature # ifndef DHT_TYPE temperature = bmp.readTemperature(); # endif // !DHT_TYPE #endif // HAVE_BMP180 // Turn off the LED to indicate work is finished digitalWrite(LED_BUILTIN, HIGH); } void loop() { unsigned long now = millis(); MDNS.update(); server.handleClient(); if (now - last_update >= 5000) { read_sensors(); last_update = now; } }