modular-weather-station/WeatherStation.ino

313 lines
7.3 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* ModularWeatherStation
*
* Copyright (C) 2021 Gergely Polonkai
* Author: Gergely POLONKAI <gergely@polonkai.eu>
*
* 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 <http://www.gnu.org/licenses/>.
*
* 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 <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266mDNS.h>
#include <ESP8266WebServer.h>
#include "config.h"
#ifdef DHT_TYPE
# include <DHT.h>
#endif // DHT_TYPE
#if defined(HAVE_BH1750) || defined(HAVE_BMP180)
# include <Wire.h>
#endif // defined(HAVE_BH1750) || defined(HAVE_BMP180)
#ifdef HAVE_BH1750
# include <BH1750.h>
#endif // HAVE_BH1750
#ifdef HAVE_BMP180
# include <Adafruit_BMP085.h>
#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 were 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;
}
}