Hallo @Stefan,
ich habe den ESP32-Code mit ESP8266 verheiratet. Und dabei meine kleinen Änderungen mit eingebracht. Bei jeder Änderung ist ein // Oliver: als Kommentar. So kann man leichter suchen.
- GSM kann ich nicht testen. Funktioniert dementsprechend nur mit “false”.
- DS18B20 teste ich, sobald ich die Komponenten in der Hand halte.
- Wifi Enterprise noch testen
- Battery Level noch testen
- Vielleicht noch die Pinbelegung zentralisieren und auf Boardauswahl anpassen.
Was ich mich beim ESP32-Code am meisten frage: Es es sinnvoll das EEPROM so stark zu belasten? Sind doch jede Menge Schreibzyklen?
Und könnte man “WUNDERGROUND” nicht weg lassen? Geht das im Dashboard mit Grafana nicht genauso gut?
So sieht der Code aktuell aus. Geht mit Sicherheit eleganter.
#include <Arduino.h>
// Sketch ist für TTGO-T-CALL mit dem SIM800 Modul ausgelegt
// Farbecode Anschlußkabel BOSCHE H40A
/*
+E Rot
+A Grün
-E Schwarz
-A Weiß
Shield Lila
*/
//Hinweis: Die WPA2 Verbindung wurde noch nicht mit dem ESP32 verifziert.
//Hinweis: Der Sensor Count für den Temperatur Sensor gibt 0 aus - Messung selbst
//Wichtig: #define MAXBUFFERSIZE (2048) in Adafruit_MQTT.h anpassen, da ansonsten nicht alle Daten übermittelt werden können
#define ESP8266 true // Oliver Boardauswahl ergänzt
#define GSM_ENABLED false //Bei FALSE wird automatisch WIFI aktiviert
#define WEIGHT true
#define SENSOR_DS18B20 true
#define SENSOR_BATTERY_LEVEL true // falls Spannungsmessung über Spannungsteiler erfolgen soll, wenn kein SIM800 Modul verwendet wird.
#define DEEPSLEEP_ENABLED true // Code ist aktuell nur auf TRUE ausgelegt, falls False, muß noch im main() ein Delay eingebaut werden.
#define SLEEP_TIMER false // SleepDauer abhängig vom Ladezustand, Sleep_Timer noch nicht mit Wifi verifziert.
#define WUNDERGROUND false // funktionert aktuell nur mit GSM_ENABLED false
#define WIFI_ENTERPRISE false // Unterstützung von WPA2 Enterprise Verschlüsselung, falls FALSE wird der WifiManager verwendet,
#define SLEEP_SHORT true // Steuerung der Sleepdauer - 5 min/15 min oder 15 min/60 min
#if GSM_ENABLED
#define WIFI_ACTIVE false
#define TINY_GSM_MODEM_SIM800
#define TINY_GSM_RX_BUFFER 1024
#include <Wire.h>
#include <TinyGsmClient.h>
#define SerialAT Serial1
// TTGO T-Call pins
#define MODEM_RST 5
#define MODEM_PWKEY 4
#define MODEM_POWER_ON 23
#define MODEM_TX 27
#define MODEM_RX 26
#define I2C_SDA 21
#define I2C_SCL 22
/* Daten für Netzclub SIM Karte
const char apn[] = "pinternet.interkom.de"; //Abhängig vom Netzprovider - ggfs.auf eigene Werte anpassen.
const char user[] = ""; //Abhängig vom Netzprovider
const char pass[] = ""; //Abhängig vom Netzprovider
*/
/*Daten für Telekom SIM
const char apn[] = "internet.telekom"; // APN (example: internet.vodafone.pt) use https://wiki.apnchanger.org
const char user[] = "t-mobile"; // GPRS User
const char pass[] = "tm"; // GPRS Password
*/
// Daten für Discotel SIM
const char apn[] = "internet"; // APN (example: internet.vodafone.pt) use https://wiki.apnchanger.org
const char user[] = ""; // GPRS User
const char pass[] = ""; // GPRS Password
// SIM card PIN (leave empty, if not defined)
const char simPIN[] = "1234"; //PIN gegen eignen Wert austauschen
int gsm_csq; //Variable für GSM Signal Stärke
#else
#define WIFI_ACTIVE true
long wifi_rssi ; // Wifi Signalstärke
#endif
#if SENSOR_BATTERY_LEVEL
int adc_level;
#endif
// Variablen für Spanungsmessung, werden unabhängig der Messmethode (Spannungsteiler o. SIM800 Modul benötigt)
int volt_level;
float voltage;
// Oliver: Library je nach Board
#if ESP8266
#include <ESP8266WiFi.h>
#else
#include <WiFi.h>
#endif
//#include <WebServer.h> // Oliver: wozu?
//#include <WiFiUdp.h> // Oliver: wozu?
#if WIFI_ACTIVE
#include <WiFiManager.h> //https://github.com/tzapu/WiFiManager
#endif
#if WIFI_ENTERPRISE
//#include "user_interface.h" // Bibliotheken zur Unterstützung der WPA2 Verschlüsselung
//#include "wpa2_enterprise.h"
#include "esp_wpa2.h"
// SSID to connect to
static const char* ssid = "Your_WPA2SSID";
// Username for authentification
static const char* username = "Your_User";
// Password for authentication
static const char* password = "Your_Password";
#endif
#if SLEEP_TIMER
#include <EEPROM.h>
int power_save_mode = 0;
int address = 1; // Willkürlich von mir festgelegt das im EEPROM an Adresse 1 der Wert für den Ladezustand abgelegt wird.
int voltbe4; // Wert der vorherigen Messung
int voltbelow = 75; // Schwellwert für die Aktivierung des PowerSave Modus (Verlängerung des SleepTimers auf 60 min)
#endif
#if SLEEP_SHORT
int sleepTimerShort = 300; //5-Minuten SleepTimer
int sleepTimerLong = 900; //15-Minuten SleepTimer
#else
int sleepTimerShort = 900; //15-Minuten SleepTimer
int sleepTimerLong = 3600; //60-Minuten SleepTimer
#endif
//int sleepTimeS = sleepTimerShort; // Oliver: Variable vorbelegt, falls Sleeptimer false.
int sleepTimeS = 20; // Oliver: Zum Testen mal verkürzt.
#define uS_TO_S_FACTOR 1000000LL
// Boot Counter - Wert wird mit jedem WakeUp des ESP hochgezählt, 0 bei Kaltstart
// Oliver: Wozu die Funktion eigentlich?
#if ESP8266
#define RTCMEMORYSTART 65
extern "C" {
#include "user_interface.h"
}
typedef struct {
int count;
} rtcStore;
rtcStore rtcMem;
#else
RTC_DATA_ATTR int bootCount = 0;
#endif
// Adafruit MQTT
// https://github.com/adafruit/Adafruit_MQTT_Library
#include <Adafruit_MQTT.h>
#include <Adafruit_MQTT_Client.h>
// JSON serializer
// https://github.com/bblanchon/ArduinoJson
#include <ArduinoJson.h>
// ----
// MQTT
// ----
// How often to retry connecting to the MQTT broker
#define MQTT_RETRY_COUNT 5
// How long to delay between MQTT (re)connection attempts (seconds)
#define MQTT_RETRY_DELAY 1.5f
// The address of the MQTT broker to connect to
#define MQTT_BROKER "swarm.hiveeyes.org"
#define MQTT_PORT 1883
// A MQTT client ID, which should be unique across multiple devices for a user.
// Maybe use your MQTT_USERNAME and the date and time the sketch was compiled
// or just use an UUID (https://www.uuidgenerator.net/) or other random value.
//#define MQTT_CLIENT_ID "xxxxxxxx-yyyy-xxxx-yyyy-zzzzzzzzzzzz" // Hier eigenen Werte eintragen
#define MQTT_CLIENT_ID "testdrive" // Oliver: meine Testumgebung
// The credentials to authenticate with the MQTT broker
// Eigenen Login Daten bei den netten Team von Hiveeyes via hello@hiveeyes.org anfragen.
#define MQTT_USERNAME "" // Benutzername, Testdrive: leer lassen
#define MQTT_PASSWORD "" // Kennwort, Testdrive: leer lassen
// The MQTT topic to transmit sensor readings to.
// Note that the "testdrive" channel is not authenticated and can be used anonymously.
// To publish to a protected data channel owned by you, please ask for appropriate
// credentials at https://community.hiveeyes.org/ or hello@hiveeyes.org.
//#define MQTT_TOPIC "hiveeyes/-------MQTT-CLIENT-ID-von-oben------/spielwiese/node-1/data.json" //ggfs. beim Pfad beim Team von hiveeyes noch nachfragen.
#define MQTT_TOPIC "hiveeyes/testdrive/oliver/node-2/data.json" // Oliver: meine Testumgebung
#if GSM_ENABLED
// I2C for SIM800 (to keep it running when powered from battery)
TwoWire I2CPower = TwoWire(0);
// Client für GSM hier aufrufen
TinyGsm modem(SerialAT);
TinyGsmClient client(modem);
TinyGsmClient clientMQTT(modem);
#define IP5306_ADDR 0x75
#define IP5306_REG_SYS_CTL0 0x00
bool setPowerBoostKeepOn(int en){
I2CPower.beginTransmission(IP5306_ADDR);
I2CPower.write(IP5306_REG_SYS_CTL0);
if (en) {
I2CPower.write(0x37); // Set bit1: 1 enable 0 disable boost keep on
} else {
I2CPower.write(0x35); // 0x37 is default reg value
}
return I2CPower.endTransmission() == 0;
}
#endif
#if WIFI_ACTIVE
WiFiClient client;
WiFiClient clientMQTT;
#endif
// Setup the MQTT client class by passing in the WiFi client and MQTT server and login details
Adafruit_MQTT_Client mqtt(&clientMQTT, MQTT_BROKER, MQTT_PORT, MQTT_CLIENT_ID, MQTT_USERNAME, MQTT_PASSWORD);
// Setup MQTT publishing handler
Adafruit_MQTT_Publish mqtt_publisher = Adafruit_MQTT_Publish(&mqtt, MQTT_TOPIC);
#if WEIGHT
#include <HX711.h>
#include <RunningMedian.h> // http://playground.arduino.cc/Main/RunningMedian
// Aktuelle HX711 Library verwendet deshalb anstatt #define -> const int und ; am Ende ;-)
//#define SCALE_DOUT_PIN_A D5 // DT
//#define SCALE_SCK_PIN_A D3 // SCK
const int SCALE_DOUT_PIN_A = 33;// DT
const int SCALE_SCK_PIN_A = 32;// SCK
//#define SCALE_DOUT_PIN_B D2 // DT
//#define SCALE_SCK_PIN_B D1 // SCK
const int SCALE_DOUT_PIN_B = 14;// DT
const int SCALE_SCK_PIN_B = 25;// SCK
HX711 scale_A;
HX711 scale_B;
long AktuellesGewicht_A = 0;
long AktuellesGewicht_B = 0;
float Taragewicht_A = 226743; // Hier ist der Wert aus der Kalibrierung einzutragen
float Skalierung_A = 41.647; // Hier ist der Wert aus der Kalibrierung einzutragen
float Taragewicht_B = -238537; // Hier ist der Wert aus der Kalibrierung einzutragen
float Skalierung_B = -42.614; // Hier ist der Wert aus der Kalibrierung einzutragen
long Gewicht_A = 999999;
float GewichtEinzelmessung_A;
long Gewicht_B = 999999;
float GewichtEinzelmessung_B;
// create RunningMedian object with 10 readings
RunningMedian GewichtSamples_A = RunningMedian(10);
RunningMedian GewichtSamples_B = RunningMedian(10);
#endif
#if SENSOR_DS18B20
// Temperatur Sensoren DS18B20 connectet to Pin 4
#define DS18B20_PIN 4
// Oliver: wieviele Sensoren werden max angeschlossen? Arraygröße muss vorbelegt werden...
// Bei Speicherproblemen reduzieren.
#define MaxDS18B20 20
// 1-Wire library
#include <OneWire.h>
// DS18B20/DallasTemperature library
#include <DallasTemperature.h>
// For communicating with any 1-Wire device (not just DS18B20)
OneWire oneWire(DS18B20_PIN);
// Initialize DallasTemperature library with reference to 1-Wire object
DallasTemperature sensors(&oneWire);
// Device Adresses - dedected by oneWireSearch.ino or Multiple similar
// Update device adress for your Sensor
/*
uint8_t Sensor1 [8] = { 0x28, 0xFF, 0xCF, 0xBD, 0xA4, 0x16, 0x04, 0x46 }; // Nr. 3 grüne Schrift
uint8_t Sensor2 [8] = { 0x28, 0xFF, 0x67, 0x65, 0x51, 0x16, 0x04, 0xEE }; // langes Kabel
// Define Variable to hold temperature value for Sensor1
float temps1;
// Define Variable to hold temperature value for Sensor2
float temps2;
*/
// Oliver: wird ersetzt durch Array
float temps[MaxDS18B20]; // Oliver: todo, geht das variabel? Wahrscheinlich nicht.
//int AnzahlDS18B20 = sensors.getDeviceCount();
int AnzahlDS18B20 = 3; // Oliver: mal zum testen geändert
#endif
#if WUNDERGROUND
// Weatherundeground
const char* weatherhost = "api.weather.com";
// TextFinder Lib used for text extractation of XML Data
#include <TextFinder.h>
// Define variable as "char" as they will be extracted via finder.string of XML Data
char currentTemp[8];
char currentHumidity[8];
// Weatherunderground Station - Alternative Station IMNCHEN1945
// Weatherunderground Station - Alternative Station IBAYERNM74
const char* WUG_Station = "IMUNICH323";
#endif
void gsm_setup();
void gsm_connect();
void gsm_disconnect();
void gsm_info();
void gsm_poweron();
void gsm_SleepMode2On();
void gsm_SleepModeOff();
bool mqtt_connect();
void transmit_readings();
void setup_weight();
void read_weight();
void setup_tempsensor();
void read_tempsensor();
void read_battery_level();
void power4sleep();
void read_weatherunderground();
void setup() {
Serial.begin(115200);
// Oliver: Neustart darstellen.
Serial.println();
Serial.println();
Serial.println("#### Restart ####");
Serial.println();
//Increment boot number and print it every reboot
// Oliver: Aus Boardauswahl angepasst. Wozu eigentlich?
#if ESP8266
Serial.println("Boot number: " + String(readFromRTCMemory()));
writeToRTCMemory();
#else
++bootCount;
Serial.println("Boot number: " + String(bootCount));
#endif
#if WIFI_ACTIVE
#if WIFI_ENTERPRISE
Serial.println("Booting WPA2 Enterprise Wifi Mode ");
// WPA2 Connection starts here
// Setting ESP into STATION mode only (no AP mode or dual mode)
/* Code für WPA2 für esp8266 - achtung auch wpa2_enterprise.h bei WIFI_ENTERPRISE notwendig
wifi_set_opmode(STATION_MODE);
struct station_config wifi_config;
memset(&wifi_config, 0, sizeof(wifi_config));
strcpy((char*)wifi_config.ssid, ssid);
wifi_station_set_config(&wifi_config);
wifi_station_clear_cert_key();
wifi_station_clear_enterprise_ca_cert();
wifi_station_set_wpa2_enterprise_auth(1);
wifi_station_set_enterprise_identity((uint8*)username, strlen(username));
wifi_station_set_enterprise_username((uint8*)username, strlen(username));
wifi_station_set_enterprise_password((uint8*)password, strlen(password));
wifi_station_connect();
*/
WiFi.disconnect(true); //disconnect form wifi to set new wifi connection
WiFi.mode(WIFI_STA); //init wifi mode
esp_wifi_sta_wpa2_ent_set_identity((uint8_t *)username, strlen(username)); //provide identity
esp_wifi_sta_wpa2_ent_set_username((uint8_t *)username, strlen(username)); //provide username --> identity and username is same
esp_wifi_sta_wpa2_ent_set_password((uint8_t *)password, strlen(password)); //provide password
esp_wpa2_config_t config = WPA2_CONFIG_INIT_DEFAULT(); //set config settings to default
esp_wifi_sta_wpa2_ent_enable(&config); //set config settings to enable function
WiFi.begin(ssid);
// WPA2 Connection ends here
/*
// Wait for connection AND IP address from DHCP
Serial.println();
Serial.println("Waiting for connection and IP Address from DHCP");
while (WiFi.status() != WL_CONNECTED) {
delay(2000);
Serial.print(".");
}*/
// Wait for connection AND IP address from DHCP
Serial.println();
Serial.println("Waiting for connection and IP Address from DHCP");
while (WiFi.status() != WL_CONNECTED) {
delay(2000);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
/*
while (WiFi.waitForConnectResult() != WL_CONNECTED) {
Serial.println("Connection Failed! Rebooting...");
Serial.println("ESP8266 in sleep for 1 min mode");
esp_sleep_enable_timer_wakeup(60 * uS_TO_S_FACTOR);
esp_deep_sleep_start();
delay(100);
}
*/
#else
Serial.println("Booting Wifi Mode ");
// Start Wifi Manager to connect
WiFiManager wifiManager;
wifiManager.setConfigPortalTimeout(60);
wifiManager.autoConnect("AutoConnectAP");
while (WiFi.waitForConnectResult() != WL_CONNECTED) {
Serial.println("Connection Failed! Rebooting...");
Serial.println("ESP8266 in sleep for 1 min mode");
//Go to sleep now
// Oliver: auf Boardauswahl angepasst
#if ESP8266
ESP.deepSleep(60 * uS_TO_S_FACTOR, WAKE_RF_DEFAULT);
delay(100);
#else
esp_sleep_enable_timer_wakeup(60 * uS_TO_S_FACTOR);
esp_deep_sleep_start();
delay(100);
#endif
}
#endif
Serial.println(WiFi.localIP().toString());
Serial.println(WiFi.SSID());
Serial.println("Ready");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
wifi_rssi = WiFi.RSSI();
Serial.print("Wifi Signalstärke: ");
Serial.println(wifi_rssi);
#endif
#if GSM_ENABLED
Serial.println(" ->");
Serial.println("Booting GSM Mode");
gsm_setup();
gsm_SleepModeOff();
gsm_connect();
gsm_info();
#endif
Serial.println(" ->");
Serial.println("Setup Weight");
setup_weight();
#ifdef SENSOR_DS18B20
Serial.println(" ->");
Serial.println("Setup Temp Sensor");
setup_tempsensor();
#endif
}
void loop() {
Serial.println("MQTT Connect");
if (!mqtt_connect()) {
return;
}
Serial.println("Read Weight");
read_weight();
Serial.println("Read Temperatur Sensor");
read_tempsensor();
Serial.println("Read Battery Level");
read_battery_level();
Serial.println("Read Weatherunderground");
read_weatherunderground();
Serial.println("Set Sleep Timer");
power4sleep();
Serial.println("Transmit Reading");
transmit_readings();
delay(1000);
#if GSM_ENABLED
gsm_disconnect();
#endif
#if DEEPSLEEP_ENABLED // Oliver: falls kein deepsleep, Delay für die gleiche Zeit
Serial.print("Going to sleep for ");
Serial.print(sleepTimeS);
Serial.println(" s");
#if ESP8266 // Oliver: auf Boardauswahl angepasst, Dauer für sleep wird ausgegeben.
ESP.deepSleep(sleepTimeS * uS_TO_S_FACTOR, WAKE_RF_DEFAULT);
delay(100);
#else
esp_sleep_enable_timer_wakeup(sleepTimeS * uS_TO_S_FACTOR);
esp_deep_sleep_start();
delay(100);
#endif
#else
Serial.println();
Serial.println();
for (int i = (sleepTimeS); i >0 ; i--) {
Serial.print("Delay for: ");
Serial.print(i);
Serial.println(" s");
delay(1000);
}
Serial.println();
#endif
}
void setup_weight() {
#if WEIGHT
scale_A.begin(SCALE_DOUT_PIN_A, SCALE_SCK_PIN_A);
scale_B.begin(SCALE_DOUT_PIN_B, SCALE_SCK_PIN_B);
// Waage A Setup
scale_A.set_offset(Taragewicht_A);
scale_A.set_scale(Skalierung_A);
// Waage B Setup
scale_B.set_offset(Taragewicht_B);
scale_B.set_scale(Skalierung_B);
#endif
}
void read_weight() {
#if WEIGHT
//clearRunningMedian Sample
GewichtSamples_A.clear();
GewichtSamples_B.clear();
// read x times weight and take median
// do this till running median sample is full
while (GewichtSamples_A.getCount() < GewichtSamples_A.getSize()) {
// wait between samples
//Serial.print("."); // Oliver: Auskommentiert. Mich stört der Punkt in der Ausgabe. Wozu dieser?
delay(180);
// power HX711 / load cell
scale_A.power_up();
scale_B.power_up();
delay(2); // wait for stabilizing
// read raw data input of HX711
// Oliver: wenn eine Waage nicht ready ist, geht es so trotzdem weiter. Waagenwert wird dann Null gesetzt
if (scale_A.wait_ready_timeout(1000)) {
GewichtEinzelmessung_A = scale_A.read();
} else {
GewichtEinzelmessung_A = 0;
}
if (scale_B.wait_ready_timeout(1000)) {
GewichtEinzelmessung_B = scale_B.read();
} else {
GewichtEinzelmessung_B = 0;
}
// switch off HX711 / load cell
scale_A.power_down();
scale_B.power_down();
// calculate weight in kg
Gewicht_A = (GewichtEinzelmessung_A - Taragewicht_A) / Skalierung_A;
Gewicht_B = (GewichtEinzelmessung_B - Taragewicht_B) / Skalierung_B;
// use calculated kg values for median statistic
GewichtSamples_A.add(Gewicht_A);
GewichtSamples_B.add(Gewicht_B);
AktuellesGewicht_A = GewichtSamples_A.getMedian();
AktuellesGewicht_B = GewichtSamples_B.getMedian();
Serial.print("Gewicht A: ");
Serial.print(AktuellesGewicht_A);
Serial.println(" g");
Serial.print("Gewicht B: ");
Serial.print(AktuellesGewicht_B);
Serial.println(" g");
}
#endif
}
void gsm_setup() {
#if GSM_ENABLED
I2CPower.begin(I2C_SDA, I2C_SCL, 400000);
// Keep power when running from battery
bool isOk = setPowerBoostKeepOn(1);
Serial.println(String("IP5306 KeepOn ") + (isOk ? "OK" : "FAIL"));
// Set modem reset, enable, power pins
pinMode(MODEM_PWKEY, OUTPUT);
pinMode(MODEM_RST, OUTPUT);
pinMode(MODEM_POWER_ON, OUTPUT);
digitalWrite(MODEM_PWKEY, LOW);
digitalWrite(MODEM_RST, HIGH);
digitalWrite(MODEM_POWER_ON, HIGH);
// Set GSM module baud rate and UART pins
SerialAT.begin(115200, SERIAL_8N1, MODEM_RX, MODEM_TX);
// Restart takes quite some time
// To skip it, call init() instead of restart()
Serial.println("Initializing modem...");
modem.restart();
// Unlock your SIM card with a PIN if needed
if ( simPIN && modem.getSimStatus() != 3 ) {
modem.simUnlock(simPIN);
Serial.print("GetSimStatus:");
Serial.print(simPIN);
}
#endif
}
void gsm_connect() {
#if GSM_ENABLED
Serial.print("Waiting for network...");
if (!modem.waitForNetwork()) {
Serial.println(" fail");
delay(10000);
return;
}
Serial.println("Connected to mobil network");
gsm_info();
Serial.print("GPRS Connecting to ");
Serial.print(apn);
if (!modem.gprsConnect(apn, user, pass)) {
Serial.println(" fail");
delay(10000);
// Falls die Verbindung mit dem GSM & GPRS Netz nicht klappt, legt sich der der ESP für 60 sec schlafen und wir starten im Anschluß von vorn.
// GSM Modem stoppen
gsm_disconnect();
// Sleep für 60 Sekunden
esp_sleep_enable_timer_wakeup(60 * uS_TO_S_FACTOR);
esp_deep_sleep_start();
delay(100);
return;
}
Serial.println("GPRS Connection established");
#endif
}
void gsm_info() {
#if GSM_ENABLED
gsm_csq = modem.getSignalQuality();
volt_level = modem.getBattPercent();
voltage = modem.getBattVoltage() / 1000.0F;
Serial.println();
Serial.println("Signal Qualität");
Serial.println(gsm_csq);
Serial.println("Akku Level ");
Serial.println(volt_level);
Serial.println("Akku Wert Spannung ");
Serial.println(voltage);
#endif
}
void gsm_disconnect() {
#if GSM_ENABLED
// For dem Sleep - Verbindung kappen
Serial.println("GPRS Disconnect");
modem.gprsDisconnect();
// For dem Sleep - Modem RadioOFF schalten
Serial.println("GSM Radio Off ");
modem.radioOff();
delay(1000);
Serial.println("GSM Sleep Mode 2 Enablen ");
gsm_SleepMode2On();
#endif
}
void gsm_SleepMode2On() {
#if GSM_ENABLED
modem.sendAT(GF("+CSCLK=2"));
delay(1000);
#endif
}
void gsm_SleepModeOff() {
#if GSM_ENABLED
modem.sendAT(GF("+CSCLK=0"));
delay(1000);
#endif
}
bool mqtt_connect() {
// If already connected, don't do anything and signal success
if (mqtt.connected()) {
return true;
}
Serial.println("Connecting to MQTT broker");
// Reconnect loop
uint8_t retries = MQTT_RETRY_COUNT;
int8_t ret;
while ((ret = mqtt.connect()) != 0) {
Serial.println("Anzahl MQTT Connection Retries:");
Serial.println(ret);
Serial.println(String(mqtt.connectErrorString(ret)).c_str());
retries--;
if (retries == 0) {
Serial.println("Giving up connecting to MQTT broker");
// Falls keine MQTT Verbindung aufgebaut werden kann, hängen wir hier ewig in der Schleife
// da solange die Funktion mqtt.connect aufgerufen wird
// deshalb fangen wir von vorne an in dem wir den ESP 1min schlafen geht und die Schleife von vorne beginnt
// GSM Modem stoppen
gsm_disconnect();
// Sleep für 60 Sekunden. // Oliver: auf Boardauswahl angepasst
#if ESP8266
ESP.deepSleep(60 * uS_TO_S_FACTOR, WAKE_RF_DEFAULT);
delay(100);
#else
esp_sleep_enable_timer_wakeup(60 * uS_TO_S_FACTOR);
esp_deep_sleep_start();
delay(100);
#endif
return false;
}
Serial.println("Retry MQTT Connection in x Seconds:");
Serial.println(MQTT_RETRY_DELAY);
// Wait some time before retrying
delay(MQTT_RETRY_DELAY * 1000);
}
if (mqtt.connected()) {
Serial.println("Successfully connected to MQTT broker");
Serial.println(MQTT_BROKER);
return true;
}
// Giving up on further connection attempts
return false;
}
void setup_tempsensor() {
#if SENSOR_DS18B20
Serial.println("Temperaturmessung mit dem DS18B20 ");
// Start Dallas Tempeartur Library / Instanz
sensors.begin(); // DS18B20 starten
// Präzision auf 12 Bit // Oliver: verringern zur zeitersparnis bei vielen Sensoren?
/*
9 bit 0.5 degrees C 94 mSec
10 bit 0.25 degrees C 188 mSec
11 bit 0.125 degrees C 375 mSec
12 bit 0.0625 degrees C 750 mSec
*/
//sensors.setResolution(TEMP_12_BIT);
sensors.setResolution(12);
//Anzahl Sensoren ausgeben
Serial.print("Sensoren: ");
Serial.println(sensors.getDeviceCount());
#endif
}
void read_tempsensor() {
#if SENSOR_DS18B20
// Temperatursensor(en) auslesen
sensors.requestTemperatures();
// Read Temperature form each Sensor
//temps1 = sensors.getTempC(Sensor1); // Oliver: Ersetzt durch nachfolgende Schleife
//temps2 = sensors.getTempC(Sensor2); // Oliver: Ersetzt durch nachfolgende Schleife
for (int i=0; i<AnzahlDS18B20; i++){
temps[i] = sensors.getTempCByIndex(i);
}
#endif
}
void read_battery_level() {
#if SENSOR_BATTERY_LEVEL
// Read the battery level from the ESP8266 analog input pin.
// Analog read level is 10 bit 0-1023 (0V-1V).
// Our 1M & 220K voltage divider takes the max
// MY 1M & 3,3 K
// LiPo value of 4.2V and drops it to 0.758V max.
// This means our minimum analog read value should be 580 (3.14V)
// and the maximum analog read value should be 774 (4.2V).
// Read Value from A0 - max 3.3V, daher etwas andere Teiler
// 1024 / 3,3 * 1,73 = 537 1,73V laut spannungsteiler bei 4,2 V mit 4,7k & 3,3k
// 1024 / 3,3 * 1,3 = 400 1,3V lt. spannungsteiler bei 3,14 V mit 4,7k & 3,3 k
adc_level = analogRead(A0);
Serial.print("ADC_level: ");
Serial.println(adc_level);
// Map Value to % Level
volt_level = map(adc_level, 400, 537, 0, 100);
Serial.println(volt_level);
// Calculate Voltage Value
Serial.print("Voltage: ");
voltage = adc_level * 4.2 / 537 ;
Serial.println( voltage );
// Give operating system / watchdog timer some breath
yield();
#endif
}
void power4sleep() {
#if SLEEP_TIMER
// Oliver: Ist es wirklich sinnvoll hier das EPROM zu belasten? Es kommen ja schon eine ganze Menge Schreibzyklen zusammen.
// Wäre das nicht auch was für den RTC-Speicher?
EEPROM.begin(512);
//letzten Ladungsstand Wert aus EEprom auslesen
voltbe4 = EEPROM.read(address);
Serial.print("Read Value:");
Serial.println(voltbe4);
//aktuellen Ladungsstand Wert in EEprom ablegen
EEPROM.write(address, volt_level );
EEPROM.commit();
if (volt_level < voltbelow && voltbe4 < voltbelow )
{
// Wenn Ladungswert unter 75% wird die Sleep Dauer auf 60 min (=3600 Sekunden) verlängert
//sleepTimeS = 3600;
// Wert wird Abhängig vom #define SLEEP_SHORT gesetzt
sleepTimeS = sleepTimerLong;
power_save_mode = 1;
}
else
{
// Wenn Ladungswert über 75% ist die Sleep Dauer auf 15 min (=900 Sekunden) gesetzt
// sleepTimeS = 900;
// Wert wird Abhängig vom #define SLEEP_SHORT gesetzt
sleepTimeS = sleepTimerShort;
power_save_mode = 0;
}
Serial.print("Set Sleep Timer to:");
Serial.println(sleepTimeS);
Serial.print("Set Power Save to:");
Serial.println(power_save_mode);
#endif
}
void read_weatherunderground() {
#if WUNDERGROUND
if (client.connect(weatherhost, 80))
{
String wurl = "/v2/pws/observations/current?apiKey=6532d6454b8aa370768e63d6ba5a832e&stationId=IMUNICH323&format=xml&units=m" ;
client.print(String("GET ") + wurl + " HTTP/1.1\r\n" + "Host: " + weatherhost + "\r\n" + "Connection: close\r\n\r\n");
while (!client.available()) {
// delay(200);
delay(10000);
Serial.print("client not availabel connect: ");
}
// Read all the lines of the reply from server and print them to Serial
TextFinder finder(client); // Keine Ahnung wozu - aber ohne intanzierung läuft der Textfinder nicht
// while (client.available()) {
String line = client.readStringUntil('\r');
finder.getString("<humidity>", "</humidity>", currentHumidity, 8) ;
finder.getString("<temp_c>", "</temp_c>", currentTemp, 8) ;
Serial.println("closing connection");
}
#endif
}
int readFromRTCMemory() {
system_rtc_mem_read(RTCMEMORYSTART, &rtcMem, sizeof(rtcMem));
yield();
return rtcMem.count;
}
void writeToRTCMemory() {
rtcMem.count++;
system_rtc_mem_write(RTCMEMORYSTART, &rtcMem, 4);
yield();
}
void transmit_readings() {
// Build JSON object containing sensor readings
// TODO: How many data points actually fit into this?
// json5: StaticJsonBuffer<1024> jsonBuffer;
// neu für json6
DynamicJsonDocument doc(512);
// Die folgende Zeile war im Beispiel - aber das obj wird nirgends verwendet
// JsonObject obj = doc.as<JsonObject>();
// Create telemetry payload by manually mapping sensor readings to telemetry field names.
// Note: For more advanced use cases, please have a look at the TerkinData C++ library
// https://hiveeyes.org/docs/arduino/TerkinData/README.html
// json5: JsonObject& json_data = jsonBuffer.createObject();
#if WUNDERGROUND
doc["WXD_Temp"] = currentTemp;
doc["WXD_Humi"] = currentHumidity;
#endif
#if SENSOR_DS18B20
for (int i=0; i<AnzahlDS18B20; i++){
doc[("temps" + String(i+1))] = temps[i];
}
#endif
#if WEIGHT
doc["Waage1"] = AktuellesGewicht_A;
doc["Waage2"] = AktuellesGewicht_B;
#endif
#if WIFI_ACTIVE
doc["Signal"] = wifi_rssi;
#endif
#if GSM_ENABLED
doc["Signal"] = gsm_csq;
#endif
#if SLEEP_TIMER
doc["power"] = power_save_mode;
#endif
doc["volt_level"] = volt_level;
doc["voltage"] = voltage;
// Debugging
// json5: json_data.printTo(Serial);
// für json6:
serializeJsonPretty(doc, Serial);
Serial.println();
// Serialize data
// json5:int json_length = json_data.measureLength();
// json5:char payload[json_length + 1];
// json5: json_data.printTo(payload, sizeof(payload));
// für json6.
String payload;
serializeJson(doc, payload);
// Publish data
// TODO: Refactor to TerkinTelemetry
// json5: if (mqtt_publisher.publish(payload)) {
// für json6:
if (mqtt_publisher.publish(payload.c_str())) {
Serial.println("MQTT publish succeeded");
} else {
Serial.println("MQTT publish failed");
}
}