304 lines
7.3 KiB
C++
304 lines
7.3 KiB
C++
#include <Arduino.h>
|
|
#include <RH_ASK.h>
|
|
|
|
#include <ESP8266WiFi.h> //https://github.com/esp8266/Arduino
|
|
#include <DNSServer.h>
|
|
#include <ESP8266WebServer.h>
|
|
#include "WiFiManager.h" //https://github.com/tzapu/WiFiManager
|
|
|
|
#include <PubSubClient.h> //MQTT
|
|
#include <ArduinoJson.h>
|
|
|
|
/**
|
|
* Baud Rate for the 433 Mhz connection.
|
|
* Caution: Must be the same for sender & receiver!
|
|
**/
|
|
#define RH_SPEED 2000
|
|
|
|
/**
|
|
* Pin for the receiver
|
|
**/
|
|
#if defined(USE_ARDUINO)
|
|
#define RH_RX_PIN 11
|
|
#elif defined(USE_ESPRESSIF)
|
|
#define RH_RX_PIN D8
|
|
#endif
|
|
|
|
#define RH_BUF_LEN 11
|
|
uint8_t rh_buf[RH_BUF_LEN];
|
|
|
|
#define RH_ASK_MAX_MESSAGE_LEN RH_BUF_LEN
|
|
|
|
const int AirValue = 800; //replace the value with value when placed in air
|
|
const int WaterValue = 345; //replace the value with value when placed in water
|
|
|
|
volatile boolean new_value = false;
|
|
|
|
const char *MQTT_BROKER = "192.168.178.74";
|
|
const char *MQTT_SENSOR_TOPIC = "living/sensor2";
|
|
const char *MQTT_CLIENT_ID = "living_mobile_sensor";
|
|
|
|
ESP8266WebServer server(80);
|
|
WiFiClient espClient;
|
|
PubSubClient mqttClient(MQTT_BROKER, 1883, espClient);
|
|
|
|
RH_ASK driver(RH_SPEED, RH_RX_PIN);
|
|
|
|
/**
|
|
* Message identifier constants:
|
|
* */
|
|
#define MSG_START 0x00
|
|
#define MSG_BAT 0x03
|
|
#define MSG_HEADER 0x05
|
|
#define MSG_ERR 0xee
|
|
|
|
char buff[20];
|
|
|
|
float Temperature = 0;
|
|
float Humidity = 0;
|
|
int soil = 0;
|
|
float SoilHumidity = 0;
|
|
long battery = 0;
|
|
|
|
long lastMillis = 0;
|
|
|
|
void handleRoot(); // function prototypes for HTTP handlers
|
|
void handleNotFound();
|
|
void reconnect();
|
|
String SendHTML();
|
|
void publishData(float temp, float humid, float soil, long battery);
|
|
void callback(char *inTopic, byte *payload, unsigned int length);
|
|
|
|
void configModeCallback(WiFiManager *myWiFiManager)
|
|
{
|
|
Serial.println("Entered config mode");
|
|
Serial.println(WiFi.softAPIP());
|
|
//if you used auto generated SSID, print it
|
|
Serial.println(myWiFiManager->getConfigPortalSSID());
|
|
}
|
|
|
|
void setup()
|
|
{
|
|
|
|
pinMode(LED_BUILTIN, OUTPUT);
|
|
Serial.begin(9600);
|
|
if (!driver.init())
|
|
{
|
|
Serial.println("init failed");
|
|
}
|
|
else
|
|
{
|
|
Serial.println("init done");
|
|
}
|
|
|
|
//WiFiManager
|
|
//Local intialization. Once its business is done, there is no need to keep it around
|
|
WiFiManager wifiManager;
|
|
//reset settings - for testing
|
|
//wifiManager.resetSettings();
|
|
|
|
//set callback that gets called when connecting to previous WiFi fails, and enters Access Point mode
|
|
wifiManager.setAPCallback(configModeCallback);
|
|
|
|
//fetches ssid and pass and tries to connect
|
|
//if it does not connect it starts an access point with the specified name
|
|
//here "AutoConnectAP"
|
|
//and goes into a blocking loop awaiting configuration
|
|
if (!wifiManager.autoConnect())
|
|
{
|
|
Serial.println("failed to connect and hit timeout");
|
|
//reset and try again, or maybe put it to deep sleep
|
|
ESP.reset();
|
|
delay(1000);
|
|
}
|
|
|
|
//if you get here you have connected to the WiFi
|
|
Serial.println("connected...yeey :)");
|
|
|
|
mqttClient.setCallback(callback);
|
|
|
|
server.on("/", handleRoot);
|
|
server.onNotFound(handleNotFound);
|
|
|
|
server.begin();
|
|
Serial.println("HTTP server started");
|
|
|
|
// switch build in led OFF (with HIGH);
|
|
digitalWrite(LED_BUILTIN, HIGH);
|
|
}
|
|
|
|
void loop()
|
|
{
|
|
|
|
uint8_t len = sizeof(rh_buf);
|
|
|
|
long ms = millis();
|
|
|
|
if (driver.recv(rh_buf, &len))
|
|
{
|
|
Serial.println("Message received.");
|
|
switch (rh_buf[0])
|
|
{
|
|
case MSG_START:
|
|
// start message
|
|
Serial.println("0x00 start byte");
|
|
break;
|
|
case MSG_HEADER:
|
|
// DHT Temperature
|
|
digitalWrite(LED_BUILTIN, LOW);
|
|
Serial.println("DHT Temp");
|
|
memcpy(&Temperature, &rh_buf[1], 4);
|
|
Serial.print(Temperature);
|
|
Serial.println(" °C");
|
|
// DHT Humidity:
|
|
Serial.println("DHT Humidity");
|
|
memcpy(&Humidity, &rh_buf[5], 4);
|
|
Serial.print(Humidity);
|
|
Serial.println(" %");
|
|
Serial.println("Soil Humidity");
|
|
memcpy(&soil, &rh_buf[9], 2);
|
|
Serial.println(soil);
|
|
SoilHumidity = (float)(map(soil, AirValue, WaterValue, 0, 100));
|
|
Serial.println(SoilHumidity);
|
|
new_value = true;
|
|
break;
|
|
case MSG_BAT:
|
|
// battery data
|
|
digitalWrite(LED_BUILTIN, LOW);
|
|
Serial.println("Battery");
|
|
memcpy(&battery, &rh_buf[1], 4);
|
|
Serial.print(battery);
|
|
Serial.println(" mV");
|
|
new_value = true;
|
|
break;
|
|
case MSG_ERR:
|
|
// error
|
|
Serial.println("0xEE error");
|
|
break;
|
|
default:
|
|
// should never happen
|
|
break;
|
|
}
|
|
}
|
|
|
|
server.handleClient();
|
|
if (!mqttClient.connected())
|
|
{
|
|
reconnect();
|
|
}
|
|
|
|
if (ms - lastMillis > 5000 && new_value)
|
|
{
|
|
publishData(Temperature, Humidity, SoilHumidity, battery);
|
|
lastMillis = ms;
|
|
new_value = false;
|
|
}
|
|
|
|
mqttClient.loop();
|
|
|
|
digitalWrite(LED_BUILTIN, HIGH);
|
|
|
|
}
|
|
|
|
void reconnect()
|
|
{
|
|
// Loop until we're reconnected
|
|
while (!mqttClient.connected())
|
|
{
|
|
Serial.println("INFO: Attempting MQTT connection...");
|
|
// Attempt to connect
|
|
if (mqttClient.connect(MQTT_CLIENT_ID))
|
|
{
|
|
Serial.println("INFO: connected");
|
|
}
|
|
else
|
|
{
|
|
Serial.print("ERROR: failed, rc=");
|
|
Serial.print(mqttClient.state());
|
|
Serial.println("DEBUG: try again in 5 seconds");
|
|
// Wait 5 seconds before retrying
|
|
//delay(5000);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
void callback(char *inTopic, byte *payload, unsigned int length)
|
|
{
|
|
Serial.println("Got RF data");
|
|
Serial.write(payload, length);
|
|
Serial.println();
|
|
|
|
// convert the byte non terminated payload to string:
|
|
char pltext[length + 1];
|
|
strncpy(pltext, (char *)payload, length);
|
|
pltext[length] = '\0';
|
|
// convert payload string to int:
|
|
int num = atoi(pltext);
|
|
Serial.println(pltext);
|
|
Serial.println("RF data sent");
|
|
}
|
|
|
|
void handleRoot()
|
|
{
|
|
server.send(200, "text/html", SendHTML());
|
|
}
|
|
|
|
void handleNotFound()
|
|
{
|
|
server.send(404, "text/plain", "Not found");
|
|
}
|
|
|
|
// function called to publish the temperature and the humidity
|
|
void publishData(float temp, float humid, float soil, long battery)
|
|
{
|
|
// create a JSON object
|
|
// doc : https://github.com/bblanchon/ArduinoJson/wiki/API%20Reference
|
|
DynamicJsonDocument doc(1024);
|
|
|
|
doc["temperature"] = (String)temp;
|
|
doc["humidity"] = (String)humid;
|
|
doc["soilhumidity"] = (String)soil;
|
|
doc["battery"] = (String)battery;
|
|
|
|
serializeJson(doc, Serial);
|
|
Serial.println("");
|
|
char data[200];
|
|
serializeJson(doc, data);
|
|
mqttClient.publish(MQTT_SENSOR_TOPIC, data, true);
|
|
yield();
|
|
}
|
|
|
|
String SendHTML()
|
|
{
|
|
String ptr = "<!DOCTYPE html> <html>\n";
|
|
ptr += "<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n";
|
|
ptr += "<title>Wiesendamm Wetter Report</title>\n";
|
|
ptr += "<meta http-equiv=\"refresh\" content=\"2\" >";
|
|
ptr += "<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}\n";
|
|
ptr += "body{margin-top: 50px;} h1 {color: #444444;margin: 50px auto 30px;}\n";
|
|
ptr += "p {font-size: 24px;color: #444444;margin-bottom: 10px;}\n";
|
|
ptr += "</style>\n";
|
|
ptr += "</head>\n";
|
|
ptr += "<body>\n";
|
|
ptr += "<div id=\"webpage\">\n";
|
|
ptr += "<h1>Wiesendamm Wetter Report</h1>\n";
|
|
|
|
ptr += "<p>Temperature: ";
|
|
ptr += (float)Temperature;
|
|
ptr += " C</p>";
|
|
ptr += "<p>Humidity: ";
|
|
ptr += (float)Humidity;
|
|
ptr += " %</p>";
|
|
ptr += "<p>Soil Humidity: ";
|
|
ptr += (float)SoilHumidity;
|
|
ptr += " %</p>";
|
|
ptr += "<p>Battery: ";
|
|
ptr += (float)battery;
|
|
ptr += " mV</p>";
|
|
|
|
ptr += "</div>\n";
|
|
ptr += "</body>\n";
|
|
ptr += "</html>\n";
|
|
return ptr;
|
|
} |