Inbetriebnahme und Weiterentwicklung der Firmware für Arduino (Bienenwaage 2.0 und 5.0)

Hallo @Andreas,

möglich wärs - ich hab mal kurz in meinen Notizen geschmökert - die Unterschiede kommen mir in den Sinn:

  • Unterschiedliche PINs Belegung
  • DeepSleep Funktion ist unterschiedlich ESP.deepsleep vs. esp_deep_sleep_start
    und bestimmt noch ein paar Kleinigkeiten die mir gerade nicht in den Sinn kommen.

Allerdings hat mich die Kombi ESP8266 & SIM800 so geärgert, das ich eigentlich keine Zeit mehr auf das Testen verwenden will. Zumal ich aktuell noch versuche meine Telegram Integration mit dem TTGO-T-Call Modul zu testen.

Aber generell möglich, wäre es bestimmt - da ich die node-esp32-generic aus der node-esp8266-generic hervorgegangen ist.

1 Like

Das verstehe ich. Alles gut, wir lassen es so wie es ist!

@Stefan

Ich hätte gleich mit deiner ESP32 Version starten sollen.Hier sind schon kleine aber feine Optimierungen eingeflossen. :sweat_smile:

Ich schreibe gerade viel bei dir ab. Mache aber trotzdem gerade meine eigene Version. Wenn ich nach und nach deine Funktionen einfüge verstehe ich es einfach besser. Und ich finde mich in meiner reduzierten Struktur besser zurecht. (kein GSM z.B.).

Den WiFi-Manager lasse ich auch weg. Ich arbeite nur mit der Library ESP8266WiFi.h. Was bietet der Manager für Mehrwert?

Damit fehlerhafte Wagenhardware nicht den Wachhund stören und zum Softreset führen, sehe ich eine Abfrage nach diesem Motto vor:

if (scale_A.wait_ready_timeout(1000)) {
  Serial.print("HX711 scale_A reading: ");
  Serial.println(scale_A.get_units(5));    // print the average of 5 readings from the ADC minus the tare weight
} else {
  Serial.println("HX711 scale_A not found.");
}

Vielleicht wäre das ja auch was für dich.

Und was ist der Vorteil von RunningMedian? Hat get_units(ANZAHL) nicht den gleichen Effekt?

1 Like

Hi Oliver,

Danke für die Blumen! Herzlichen Dank an dieser Stelle auch an @Stefan, der aus der groben Struktur des Codes node-wifi-mqtt.ino von @clemens und @karsten für unseren Basic WiFi/MQTT sensor node die beiden hervorragenden node-esp8266-generic.ino sowie node-esp32-generic.cpp gemacht hat [1].

Ich hoffe, dass ich bald einmal Zeit finden werde, beiden auch einen entsprechenden Platz bei Firmware overview - Hiveeyes Arduino einräumen und entsprechend dokumentieren zu können – Fragen dazu und pull requests welcome… ;].

Ich verstehe diese Herangehensweise voll und ganz. Es wäre jedoch ganz grandios, wenn wir gegen Ende Deiner Erschließungsarbeiten trotzdem versuchen könnten, Änderungen ggf. wieder in eine kanonische Version zurückzuführen. Ich weiß das ist manchmal aufwendig, wenn man einmal etwas beieinander hat, das man sich selbst erschlossen hat. Zukünftige Mitstreiterinnen werden es uns aber danken, vielleicht können wir Dich also auch dafür gewinnen?

Diese Implementierung kompensiert “misreadings” des HX711 gleichermaßen auf elektronischer Ebene [2] wie auch durch Windböen, die an der Beute angreifen. @clemens kann Dir vielleicht noch genaueres dazu sagen.

Viele Grüße,
Andreas.


  1. Nach Rücksprache mit @clemens würden wir dort gerne noch einfließen lassen, mehrere (beliebig viele) DS18B20-Sensoren auslesen zu können, um eine 1A-Unterstützung für das Open Hive Temperature Array zu bieten. @clemens hatte das in seinem Ur-Sketch bei arduino/node-gprs-http/node-gprs-http.ino at 0.16.0 · hiveeyes/arduino · GitHub ff. schon getan – @einsiedlerkrebs und ich haben uns darauf aufbauend bereits um eine verbesserte Lösung bemüht, siehe arduino/node-gprs-any/node-gprs-any.ino at 0.16.0 · hiveeyes/arduino · GitHub und arduino/libraries/OpenHive/OpenHiveTemperatureArray.cpp at 0.16.0 · hiveeyes/arduino · GitHub.

    @Stefan hatte unsere Bemühungen rund um TerkinData C++ - Hiveeyes Arduino bereits an entsprechender Stelle in seinem Code vermerkt, siehe arduino/node-esp32-generic/node-esp32-generic.cpp at b9e6482f00eddcc47b37c718e16d3ba1716bb955 · hiveeyes/arduino · GitHub.

    Ich weiß, dass das in Richtung “fortgeschritten” geht, aber wir haben im Kernteam knappe Ressourcen und hoffen, dass wir es mit vereinten Kräften schaffen könnten. ↩︎

  2. Siehe auch Analyse und Diskussion um eine korrekte Integration des HX711. ↩︎

2 Likes

An das hatte ich auch schon gedacht, als ich das Beispiel “Simple” von der Dallas library aufgerufen hatte. Und war ja klar, dass das schon mal jemand angegangen hat. Ich denke wenn man das Thema angeht,

kann man auch gleich diesbezüglich alles auf ein Level heben. Input liefere ich da gerne. Da bei mir das meiste Learning by Doing ist, müssen meine Vorschläge aber nicht immer die elegantesten sein. Ich bin aber stets bemüht. :innocent: :grin:.

Du könntest damit – ohne den ESP per USB oder FTDI zu verbinden – einfach deine WLAN-Zugangsdaten mit deinem Handy oder Rechner ändern. Auf dem Rechner muss auch nicht dir Arduino-IDE installiert sein samt der ganzen Bibliotheken.

Fürs WLAN alleine ist das momentan vielleicht nicht notwendig, da du für die Justierung der Waage eh einen Rechner mit Arduino-IDE, Bibliotheken, USB-Kabel usw. brauchst.

Wenn aber auch die Justierung der Waage darüber gehen würde und die grobe Konfiguration, könnte man im Imkerverein später mal 20 solcher Dinge “flashen” und die Leute können vor Ort ihre Waage einrichten, ohne dich oder einen Rechner mit “Vollausstattung” zu benötigen, so wie wir es auch beim BOB-Projekt machen, hier siehst du, wie das ausschauen könnte: Installation und Inbetriebnahme des Bee Observer Sensor-Kit

Das hier ist die grundlegende Funktion, auf der get_units() aufbaut. Wie du siehst wird hier das arithmetische Mitte / Mittelwert / der Durchschnitt / mean berechnet:

Und hier ein fiktiver Beispieldatensatz:

Rohwerte Mittelwert Median
1, 2, 3, 4, 5, 6, 7, 97 15.6 4,5

Du siehst also, dass der Median deutlich robuster gegenüber Ausreißern ist, das ist genau das was wir hier wollen und brauchen! Ein Ausreißer geht immer mit in die Mittelwertsberechnung ein, gerade bei hohen Ausreißern führt das zu Werten die teilweise gar nicht mehr plausibel sind und trotz Mittelwertbildung “falsch” sind. Beim Median ist das anders.

3 Likes

Coole Sache mit dem Wifimanager.

Und das mit dem Median habe ich vermutet, habe es aber wie gesagt noch nicht genau angeschaut.

Ich habe ein Problem. Wenn ich deepSleep aktiviere, funktioniert laut serieller Ausgabe alles wie vorher. Allerdings kommen keine Daten im Dashboard an? :bowing_man:

Das habe ich in der loop-Schleife mal ergänzt:

if (deepSleepActive){
  Serial.println("Schlafenszeit");
  ESP.deepSleep(sleepTimeS * 1000000, WAKE_RF_DEFAULT);
  delay(100);
} else {
  for (int i = 0; i <= (sleepTimeS); i++) {
    delay(1000);
  }
}
#define deepSleepActive false  //alles funktioniert prima
#define deepSleepActive true   //der Schein trügt

Ich habe für deepSleep sämtliche Optionen (WAKE_RF_DEFAULT , WAKE_RFCAL , WAKE_NO_RFCAL , WAKE_RF_DISABLED) ausprobiert. Ohne Veränderung.

Etwas OT hier: Der ESP8266 kann nur ca. eine Stunde schlafen. Auch das ist beim ESP32 anders. Welche deep sleep Zeit hast du denn eingestellt?

20 Sekunden. Keine Ahnung was ihm an meinem Code nicht passt. Back to the roots. Ich habe wieder den ESP8266-Code von Stefan genommen und minimal angepasst. Hat diesmal gut geklappt.
Jetzt läuft er ohne Absturz, oder bleibt hängen, wenn keine Waage richtig angeschlossen ist. Und auch der DeepSleep funktioniert.

Leider finde ich meine DS18B20 im Moment nicht. Sonst würde ich den Teil auch gleich überarbeiten. Vielleicht baue ich aus meiner Offlinewaage welche aus, wenn sie nicht mehr auftauchen. Auf China kann ich nicht warten. :laughing:

Hallo @Oliver schon zu lesen das Du voran kommst.

Ich bilde mir ein das ich mich erinnern kann das ich auch das Thema hatte wenn keine Waage angeschlossen war. Auch bei der esp32 Variante ist mir das Phänomen begegnet.

Wenn ich richtig gelesen habe, haben @clemens & @Andreas dazu beigetragen die HX711 Library zu verbessern. Vielen Dank euch beiden!

Gibt jetzt wohl auch einen HX711 non-blocking-mode

1 Like

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");
      }

    }

Hallo @Oliver,

ich hab mal angefangen Deine Anregungen und Vorarbeiten auf zunehmen.

Als erstes würde ich vorschlagen den Code direkt abhängig von der gewählten Board Architektur zu machen, so muß man gar keine Variable setzen.
Da wir die Sleep Funktion öfter brauchen und diese auch Board abhängig ist, habe ich diese in eine Funktion ausgelagert.

void esp2sleep(int dauer) {

#if defined(ARDUINO_ARCH_ESP8266)

    ESP.deepSleep(dauer * uS_TO_S_FACTOR, WAKE_RF_DEFAULT);
    delay(100);
    
 #elif defined(ARDUINO_ARCH_ESP32)

    esp_sleep_enable_timer_wakeup(dauer * uS_TO_S_FACTOR);
	  esp_deep_sleep_start();
    delay(100);   

#endif

}

Wenn es ne elegante Möglichkeit gibt nen Wert über den DeepSleep zu “retten” wäre das top. Als ich vor nem Jahr mit dem SIM 800 Modul und dem ESP8266 angefangen habe, ist mir nichts bessere eingefallen.

Aktuell ist der Boot Counter unnötig - ich habe in einer anderen Version eine Telegram Schnittstelle mit Wartungsfunktion- siehe auch Schwarmalarm & Wartungsmodus via Telegram

Bei einem Restart wurde da auch eine Nachricht gesendet die über den Coldboot informiert.
Die Funktionalitäten hätte ich eigentlich gerne wieder implementiert- aber leider bekomme ich Telegram nicht mit dem SIM800 Modul zum laufen.

Hallo @Stefan und @Oliver,

Ich habe gerade etwas an ringlabs/bienenwaage-5.0 geschafft und die Umgebung ein wenig weitergebracht. Es gibt nun erste Dokumentationsschnipsel und weiterhin wurde die von Stefan begonnene platformio.ini nun um ein Makefile erweitert, so dass man die komplette Firmware direkt aus dem Verzeichnis heraus per make bauen kann, ohne die Umgebung inkl. Bibliotheken mühselig mit der klassischen Arduino IDE einrichten zu müssen.

Gerade eben habe ich noch den Bezug der Wetterdaten von Weather Underground auf JSON umgestellt, was ich aber noch nicht getestet habe. Ich hoffe es klappt, ggf. findet Ihr Zeit, das einmal unter die Lupe zu nehmen?

Viele Grüße,
Andreas.

1 Like

Hallo @Andreas,

ganz herzlichen Dank für die wirklich tolle Dokumentation- sieht richtig Klasse aus- bin tief beeindruckt.

Die Umstellung der WeatherUnderground Daten auf JSON finde ich genial und hab mich schon an die ersten Tests gemacht - nach einer kleinen Erweiterung hat es dann auch prompt geklappt.

Dabei hab ich denn auch noch ein wenig experimentiert und hab es zum ersten Mal geschafft Daten auch per GSM von Weather Underground abzuziehen.

Hoffentlich kann ich bald mehr berichten!

Nochmal ein ganz großes Dankeschön an Dich!

2 Likes

Hallo @Stefan,

schön, dass Dir die Erweiterungen gefallen.

Exzellent! Ich hatte schon befürchtet, dass ich die Sache durch die Umstellung verschlimmbessert habe. Ich freue mich darauf, wenn Deine Fixes wieder Downstream im Repository landen.

Wunderbar!

Gern geschehen!

Sag, funktioniert denn auch das Build-Environment aka. »Just type "make"« für Dich? Wie Du vielleicht gesehen hast, habe ich bei GitHub - daq-tools/Adafruit_MQTT_Library at maxbuffersize-2048 einen Fork der Adafruit_MQTT_Library hinterlegt, der – Nomen est omen – MAXBUFFERSIZE auf 2048 bytes erhöht, damit alles passt. Diese wird wiederum in der platformio.ini angezogen:

https://github.com/hiveeyes/arduino/blob/master/node-esp32-generic/platformio.ini#L29-L29

Viele Grüße,
Andreas.

Ui, hier ist ja einiges passiert. Ich hatte das Thema stumm geschaltet? :thinking:
Ich bin gerade viel am Testen. Ich denke demnächst zeige ich mal was ich weiter gebastelt habe.
Aktuell habe ich ein Problem. Ich habe jetzt einen Temperaturrechen installiert. Folglich gibt es deutlich mehr Werte zu übertragen. Hierbei stürzt der ESP32 und auch ESP8266 dann ab. Ich denke es hat mit der Zeichenzahl zu tun. Aber ich weiß nicht, wo ich ansetzen kann? Oder ist das serverseitig limitiert?

Serielle Ausgabe:

Transmit Reading
{
  "Temp1": 23.125,
  "Temp2": 21.75,
  "Temp3": 23.125,
  "Temp4": 21.75,
  "Temp5": 23.125,
  "Temp6": 21.75,
  "Temp7": 21.75,
  "Temp8": 21.75,
  "Temp9": 21.75,
  "Signal": -53,
  "volt_level": 0,
  "voltage": 0
}
Guru Meditation Error: Core  1 panic'ed (LoadProhibited). Exception was unhandled.
Core 1 register dump:
PC      : 0x40151ab0  PS      : 0x00060630  A0      : 0x800e25ae  A1      : 0x3ffb1e60  
A2      : 0x3ffc10c8  A3      : 0x3ffc10ea  A4      : 0x000000e0  A5      : 0x00000000  
A6      : 0x000000fa  A7      : 0x00000000  A8      : 0x800e257c  A9      : 0x3ffb1e40  
A10     : 0x61746c6f  A11     : 0x3ffcc00c  A12     : 0x000000aa  A13     : 0x0000ff00  
A14     : 0x00ff0000  A15     : 0xff000000  SAR     : 0x00000008  EXCCAUSE: 0x0000001c  
EXCVADDR: 0x0000003c  LBEG    : 0x40001699  LEND    : 0x400016aa  LCOUNT  : 0xfffffffc  

Backtrace: 0x40151ab0:0x3ffb1e60 0x400e25ab:0x3ffb1e80 0x400e2611:0x3ffb1ea0 0x400e271f:0x3ffb1ec0 0x400d2365:0x3ffb1ee0 0x400d240d:0x3ffb1f90 0x400e53c1:0x3ffb1fb0 0x40089051:0x3ffb1fd0

Rebooting...
ets Jun  8 2016 00:22:57

rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0018,len:4
load:0x3fff001c,len:1044
load:0x40078000,len:8896
load:0x40080400,len:5816
entry 0x400806ac

Also bei etwas über 150 zu übertragenden Zeichen funktioniert die Übertragung nur noch sporadisch. Von daher vermute ich mal, dass hier der Watchdog Probleme macht.
Am Programmcode kann ich da ja nichts machen.

if (mqtt_publisher.publish(payload.c_str())) {     // <- da drin hängter sich auf.
  Serial.println("MQTT publish succeeded");
} else {
  Serial.println("MQTT publish failed");
}

Müsste ja dann in der Library verändert werden? Oder muss man sich mit dem Limit abfinden? Vielleicht 2 getrennte Übertragungen durchführen? Gefällt mir aber nicht so richtig…

Gerade was in den Programmkommentaren gelesen:

  • #define MAXBUFFERSIZE (2048) in Adafruit_MQTT.h anpassen,
    da ansonsten nicht alle Daten übermittelt werden können.

Mal testen :sweat_smile:

Ok. Funktioniert. Den Ärger hätte ich mir sparen können. Peinlich. :stuck_out_tongue_closed_eyes:

4 Likes

Sooo. Ich wollte euch mal zeigen, was ich aus Stefan seinem Programm für mich gebastelt habe. @Stefan, @Andreas die zwischenzeitlichen Änderungen von euch habe ich jetzt noch nicht nachvollzogen um ehrlich zu sein. :sweat_smile:
00_hiveeyesStefan32RTCmodOliver.zip (16,2 KB)

  • Ich habe das Programm umstrukturiert. Ich finde so die ganzen Einstellungen leichter.
  • Bootcounter über RTC-Speicher. Allerdings muss noch initial mal auf Null gesetzt werden. Umsetzung fehlt, da ich das für mich erst mal nicht gebraucht habe. Hochzählen ab dem Zufallswert an sich funktioniert.
  • Den Vorschlag für die automatische Boarderkennung EP32 / ESP8266 habe ich übernommen. Nicht aber die ausgelagerte Funktion. Stupides Ersetzen war erst mal einfacher.
  • Es können jetzt BMx280 Sensoren angeschlossen werden.
  • Als Alternative zum deepsleep wartet der Programmablauf jetzt genauso lange im delay.
  • Das Programm läuft weiter, auch wenn keine Waage erkannt wird.
  • Batterylevel wird über #defines des Spannungsteiler etc. automatisch berechnet.
  • Es können beliebig viele DS18B20 Sensoren angeschlossen werden. (Ist nur durch Speichervorbelegung reduziert, derzeit auf 20). Kann in den Settings einfach eingestellt werden.
  • Adressen der DS18B20 müssen nicht mehr rausgesucht werden. Man kann jedem Sensor eine ID übergeben. Diese wird im Sketch abgerufen und der Bezeichner danach erstellt. Es kann also auch ein defekter Sensor einmal ausgetauscht werden, ohne die Adresse neu vergeben zu müssen. Setzen der IDs über die Beispieldatei DallasTemperature - UserDataWriteBatch.ino. Ich habe mir das ein bisschen zurecht gebogen, um mehrere Sensoren individuell mit einer ID zu versehen. Kann ich hier auch mal noch gerne posten.

Was haltet ihr von der Umsetzung der DS18B20 und den IDs?

So wie nachfolgend dargestellt könnte man die Indizierung der DS18B20 vornehmen. Ginge natürlich noch anwenderfreundlicher, aber man braucht es auch nicht übertreiben. Ist ja eher Beiwerk.
Es werden alle gefundenen Sensoren nacheinander durchgegangen und können mit einem Zahlenwert belegt werden. Die Temperaturen werden zwischendrin immer aktualisiert. So kann man z.B. durch Erwärmen dann den angewählten Sensor suchen und dann nummerieren.

    #include <OneWire.h>
    #include <DallasTemperature.h>

    #define ONE_WIRE_BUS      21

    OneWire oneWire(ONE_WIRE_BUS);
    DallasTemperature sensors(&oneWire);

    byte deviceCount = 0;

    unsigned long previousMillis = 0;
    const long interval = 3000;


    void setup() {
      sensors.begin();
      sensors.requestTemperatures();
      Serial.begin(115200);
      
      Serial.println();
      Serial.println("########### Restart ############");
      Serial.println();
      
      deviceCount = sensors.getDeviceCount();
      Serial.print("#devices: ");
      Serial.println(deviceCount);
      Serial.println();
      
      

      for (byte i = 0; i < deviceCount; i++)
      {
      Serial.println("------------------------------------------");
      Serial.println("Enter ID for marked sensor");
      Serial.println("------------------------------------------");
      deviceInfos(i);
      
      int c = 0;
      int id = 0;
      while (c != '\n' && c != '\r')
      {
        unsigned long currentMillis = millis();
        if (currentMillis - previousMillis >= interval) {
          previousMillis = currentMillis;
          Serial.println("------------------------------------------");
          deviceInfos(i);
        }
        c = Serial.read();
        switch(c)
        {
        case '0'...'9':
          id *= 10;
          id += (c - '0');
          break;
        default:
          break;
        }
      }
      DeviceAddress t;
      sensors.getAddress(t, i);
      sensors.setUserData(t, id);

      }
      
      Serial.println();
      Serial.println("### END ###");
      deviceInfos(-1);

    }


    void loop() {

    }


    void deviceInfos(int index){
      for (byte i = 0; i < deviceCount; i++)
      {
        sensors.requestTemperatures();
        DeviceAddress t;
        sensors.getAddress(t, i);
        printAddress(t);
        Serial.print("  Temp: ");
        Serial.print(sensors.getTempC(t));
        Serial.print("  ID: ");
        int id = sensors.getUserData(t);
        Serial.print(id);
        if (index == i){
          Serial.print("  <---");
        }
        Serial.println();
      }
    }



    void printAddress(DeviceAddress deviceAddress)
    {
      for (byte i = 0; i < 8; i++)
      {
        // zero pad the address if necessary
        if (deviceAddress[i] < 16) Serial.print("0");
        Serial.print(deviceAddress[i], HEX);
      }
    }


    int serial_read_number() {
      int c = 0;
      int id = 0;
      while (c != '\n' && c != '\r')
      {
        //Serial.println();
        c = Serial.read();
        switch(c)
        {
        case '0'...'9':
          id *= 10;
          id += (c - '0');
          break;
        default:
          break;
        }
      }
      return id;
    }
2 Likes

Damit kann man ins EEPROM jedes der DS18X20-Sensoren eigene Werte zur individuellen Wiedererkennung schreiben? Saustark – das war mir nicht bewusst!

2 Likes

Ja, ich habe das auch erst in den neuen Beispielen der Library entdeckt.

Mit dem Sketch aus der Library bekommen alle Sensoren am Bus die gleiche Id. Man kann also alle Sensoren anschließen. Vergibt allen die letzte Id. Zieht den letzten ab, vergibt n-1 usw… Am Ende alle wieder anschließen und fertig. Ist vermutlich das schnellste.
Oder man schließt immer nur einen Sensor an. Oder oder oder.
Ich habe sie verlötet. Von daher muss ich den Sketch von mir nutzen.