Navigation

    Logo
    • Register
    • Login
    • Search
    • Recent
    • Tags
    • Unread
    • Categories
    • Unreplied
    • Popular
    • GitHub
    • Docu
    • Hilfe
    1. Home
    2. ltathome

    NEWS

    • Neuer Blog: Fotos und Eindrücke aus Solingen

    • ioBroker@Smart Living Forum Solingen, 14.06. - Agenda added

    • ioBroker goes Matter ... Matter Adapter in Stable

    L
    • Profile
    • Following 0
    • Followers 0
    • Topics 2
    • Posts 20
    • Best 2
    • Groups 1

    ltathome

    @ltathome

    Starter

    2
    Reputation
    30
    Profile views
    20
    Posts
    0
    Followers
    0
    Following
    Joined Last Online

    ltathome Follow
    Starter

    Best posts made by ltathome

    • RE: Füllstandsmessung per Pegelsonde.

      @ltathome Ich habe noch ein wenig experimentiert mit dem Code:

      wenn man die Ermittlung der Uptime z.B. so macht und das Zusammenbauen des Strings nicht doppelt (an mehreren Stellen), dann kommt man mit der Code-Size runter (Fragmente):

      ...
      int secs = 0, mins = 0, hours = 0;
      int days = 0;
      char uptime[25];
      ...
      void set_uptime() {
          secs++;
          secs = secs % 60;
          if (secs == 0) {
              mins++;
              mins = mins % 60;
              if (mins == 0) {
                  hours++;
                  hours = hours % 24;
                  if (hours == 0) {
                      days++;
                      days = days % 10000;   // Nach 9999 Tagen zurück auf 0 (das sind 27 Jahre....)
                  }
              }
          }
          sprintf(uptime, "%4dd %2dh %2dm", days, hours, mins);
      }
      ... 
          // System 
          /*  
          String upsum;
          upsum = String(days);
          upsum = String(upsum + "d ");
          upsum = String(upsum + hours);
          upsum = String(upsum + "h ");
          upsum = String(upsum + mins);
          upsum = String(upsum + "m");
          upsum.toCharArray(buff, 25);
          */
          client.publish("Zisterne/Uptime", uptime); 
      
      posted in Praktische Anwendungen (Showcase)
      L
      ltathome
    • RE: Füllstandsmessung per Pegelsonde.

      @Eisbaeeer ok - das NT wird auch nicht warm - insofern war das wohl böser Zufall. Das NT hat sich schleichend verabschiedet - zuerst ging das Display aus - und dann wieder an (für ne Zeit) und dann war das Ding komplett tot.

      posted in Praktische Anwendungen (Showcase)
      L
      ltathome

    Latest posts made by ltathome

    • RE: Füllstandsmessung per Pegelsonde.

      @Eisbaeeer ok - das NT wird auch nicht warm - insofern war das wohl böser Zufall. Das NT hat sich schleichend verabschiedet - zuerst ging das Display aus - und dann wieder an (für ne Zeit) und dann war das Ding komplett tot.

      posted in Praktische Anwendungen (Showcase)
      L
      ltathome
    • RE: Füllstandsmessung per Pegelsonde.

      @Eisbaeeer - mal noch eine Frage zu deinem "Original": Wieviel Watt nimmt die Schaltung Strom/Spannungswandler, Nano mit Ethernetshiel auf - mein Netzteil 5V 3 Watt ist nach 6 Monaten Betrieb abgeraucht und bevor ich das "stumpf" ersetze, wüsste ich gerne ob das an der Leistungsaufnahme lag.

      posted in Praktische Anwendungen (Showcase)
      L
      ltathome
    • RE: Füllstandsmessung per Pegelsonde.

      @Maze77 said in Füllstandsmessung per Pegelsonde.:

      Hierbei ist mir ein Fehler in deinem Skript aufgefallen @Eisbaeeer und zwar bei der Glättung des Analogen Messwertes.
      Der Fehler fällt bei deinen 60 Messungen nicht wirklich stark ins Gewicht, aber er ist da Bei 2 Messungen liegst du um 100% daneben. Du hast vergessen den Wert "fuel" wieder zu resetten. Somit addierst du auf den alten Wert die neuen hinzu. Der Fehler liegt somit bei (messungen+ 1) / (messungen).
      Die eine Zeile im Code behebt den Fehler.
      // Werte aufaddieren
      fuel = 0; // Initialisierung HINZUGEFÜGT, da Berechnung sonst falsch
      for (int i = 0; i < messungen; i++)
      {
      fuel = fuel + myArray[i];
      }
      // Summe durch Anzahl
      fuel = fuel / messungen;

      hui - das dürfte stimmen...
      @Eisbaeeer : meine Version im Diff hat zwar einen anderen Namen für die Variable aber noch den gleichen Fehler.

      posted in Praktische Anwendungen (Showcase)
      L
      ltathome
    • RE: Füllstandsmessung per Pegelsonde.

      @Eisbaeeer said in Füllstandsmessung per Pegelsonde.:

      @ltathome Da hast du mir ja ein paar Zeilen Code verheimlicht 😉
      ABER der diff hat alles gerettet. Hab eben den Code aktualisiert und fehlerfrei compiliert. Werde ihn die nächsten Tage hoffentlich mal einspielen, testen und in Github hochladen.
      Danke für die Anpassung.
      Gruß Eisbaeeer

      Ich hatte erwartet, dass klar ist, dass das nur die wesentlichen Ausschnitte waren - sorry.

      posted in Praktische Anwendungen (Showcase)
      L
      ltathome
    • RE: Füllstandsmessung per Pegelsonde.

      Hi - das Thema pull-Request hatten wir neulich schon mal auch per Chat - hatten wir dann nicht weiterverfolgt. Ich hab dir hier den diff beigepackt: patch.diff

      und kann dir gerne helfen die wichtigen Stellen zu erklären - melde dich halt.

      Grundsätzlich folgendes angepackt:
      einen Pin (PIN 2) als Input-Pin deklariert:

      #define MODE_PIN 2
      #define MODE_ZISTERNE 0
      #define MODE_HAUSWASSER 1
      #define MODE_AUTO 2
      #define MODE_COUNT 10
      bool setmode = false;
      const char *modes[] = {"Zisterne", "Hauswasser", "Auto"};
      int mode_count = MODE_COUNT;
      int mode = MODE_AUTO;
      int old_mode = MODE_AUTO;
      int pin_stat;
      int old_stat;
      

      der wird im loop auf Low/high-Übergänge geprüft und mit erstem auslösen setzt sich das System in einen "Mode-Change" Modus für 10 sekunden, in dem jeder weitere Übergang die Modi durchschaltet und den Countdown wieder auf 10 Sekunden setzt (damit das nicht prellt, zwischen den Übergängen 200ms delay:

          pin_stat = digitalRead(MODE_PIN);
          pinMillis = millis();
          if (pin_stat == LOW) {
              if (pinMillis - lastMillis > 200) {
                  //USE_SERIAL.println("Impuls Low");
                  lastMillis = pinMillis;
                  mode_count = MODE_COUNT;
                  if (!setmode) {
                      setmode = true;
                      old_mode = mode;
                      //sprintf(buf, "Enter Settings-Mode %d (%s)", mode, modes[mode]);
                      //USE_SERIAL.println(buf);
                  } else {
                      mode--;
                      if (mode < 0) {
                          mode = 2;
                      }
                      //sprintf(buf, "Mode change to %d (%s)", mode, modes[mode]);
                      //USE_SERIAL.println(buf);
                  }
              }
          }
      

      Wenn im Settingsmodus - den Zähler runterzählen und sonst die entscheidung treffen, ob das Ventil umzuschalten ist (Limits)

              if (setmode) {
                  mode_count--;
                  if (mode_count <= 0) {
                      //sprintf(buf, "leaving Settings-Mode - change from %d to %d (%s)", old_mode, mode, modes[mode]);
                      //USE_SERIAL.println(buf);
                      old_mode = mode;
                      setmode = false;
                  }
              }
              if (!setmode) {
                  if (mode == MODE_ZISTERNE) {
                      new_valve = VALVE_ZISTERNE;
                      reason = 0;
                  } else if (mode == MODE_HAUSWASSER) {
                      new_valve = VALVE_HAUSWASSER;
                      reason = 0;
                  } else if (mode == MODE_AUTO) {
                      if (liter >= limit_high) {
                          new_valve = VALVE_ZISTERNE;
                          reason = 1;
                      }
                      if (liter <= limit_low) {
                          new_valve = VALVE_HAUSWASSER;
                          reason = 2;
                      }
                  }
              }
              /*-----------------------------------------------------------
               * Wenn Ventil umzuschalten ist
              */
              if (new_valve != valve) {
                  valve = new_valve;
                  digitalWrite(VALVE_PIN, valve);
                  //sprintf(buf, "Set Valve to %s (%s)", valves[valve], reasons[reason]);
                  //USE_SERIAL.println(buf);
              }
      

      Einen PIN (3) als Ausgang für das Ventil-Relais:

      
      #define VALVE_PIN 3
      #define VALVE_ZISTERNE LOW
      #define VALVE_HAUSWASSER HIGH
      int valve = VALVE_ZISTERNE;
      int new_valve = VALVE_ZISTERNE;
      int reason = 0;
      const char *valves[] = {"Zisterne", "Hauswasser"};
      const char *reasons[] = {"manuelle Steuerung", "Automatik voll", "Automatik leer"};
      
      

      Die MQTT-Publishes erweitert:

      void Mqttpublish(void) {
              if (mqttclient.connected()) {
                  dtostrf(analog, 5, 2, buf);
                  mqttclient.publish("Zisterne/Analog", buf);
                  dtostrf(liter, 5, 0, buf);
                  mqttclient.publish("Zisterne/Liter", buf);
                  dtostrf(limit_low, 1, 0, buf);
                  mqttclient.publish("Zisterne/LiterLow", buf);
                  dtostrf(limit_high, 1, 0, buf);
                  mqttclient.publish("Zisterne/LiterHigh", buf);
                  dtostrf(percent, 5, 0, buf);
                  mqttclient.publish("Zisterne/Prozent", buf);
                  
                  if (mode == 2) {
                      mqttclient.publish("Zisterne/Modus", "Auto");
                  } else {
                      mqttclient.publish("Zisterne/Modus", "Manuell");          
                  }
                  dtostrf(mode, 1, 0, buf);
                  mqttclient.publish("Zisterne/Mode", buf);
                  dtostrf(valve, 1, 0, buf);
                  mqttclient.publish("Zisterne/Valve", buf);
                  mqttclient.publish("Zisterne/Ventil", valves[valve]);
          
                  // System
                  mqttclient.publish("Zisterne/Uptime", uptime);
              } else {
                  MqttConnect(mqttuser, mqttpass);  
              }
          }
      

      und natürlich den Subscribe eingebaut:

      
      
      void MqttConnect(char *user, char* pass) {
      
          mqttclient.setClient(ethClient);
          mqttclient.setServer(mqttserver, mqttport);
          mqttclient.setCallback(MqttCallback);
          
          mqttconnected = mqttclient.connect(MQTT_ID, user, pass);
          if (mqttconnected) {
              // USE_SERIAL.println("Connected to Mqtt-Server");
              mqttclient.subscribe("Zisterne/cmnd/Mode");
              mqttclient.subscribe("Zisterne/cmnd/Limit");
              mqttclient.subscribe("Zisterne/Mode");
              // USE_SERIAL.println("subscribing to Zisterne/cmnd/Mode");
          }
      }
      
      

      sowie den Callback definiert:

      
      void MqttCallback(char *topic, byte *payload, unsigned int length) {
          char *payloadvalue;
          char *payloadkey;
      
          payload[length] = '\0';
          payloadkey = (char *)&payload[0];
      
          // USE_SERIAL.println(payloadstring);
          if (strcmp(topic, "Zisterne/cmnd/Mode") == 0 || strcmp(topic, "Zisterne/Mode") == 0) {
              if (strcmp(payloadkey, "0") == 0 || strcmp(payloadkey, "Zisterne") == 0) {
                  mode = MODE_ZISTERNE;
              } else if (strcmp(payloadkey, "1") == 0 || strcmp(payloadkey, "Hauswasser") == 0) {
                  mode = MODE_HAUSWASSER;
              } else if (strcmp(payloadkey, "2") == 0 || strcmp(payloadkey, "Auto") == 0) {
                  mode = MODE_AUTO;
              }
          } else if (strcmp(topic, "Zisterne/cmnd/Limit") == 0) {
              int eq = 0;
              for (int i = 0; i < length; i++) {
                  if (payload[i] == '=') {
                      eq = i;
                      break;
                  }
              }
              if (eq > 0) {
                  payload[eq++] = 0;
                  payloadvalue = (char *)&payload[eq];
                  if (strcmp((char *)payload, "Low") == 0 || strcmp((char *)payload, "low") == 0) {
                      limit_low = atoi(payloadvalue);
                  }
                  if (strcmp((char *)payload, "High") == 0 || strcmp((char *)payload, "high") == 0) {
                      limit_high = atoi(payloadvalue);
                  }
              }
          }
      }
      

      wie gesagt - melde dich, wenn ich helfen kann/soll.

      posted in Praktische Anwendungen (Showcase)
      L
      ltathome
    • RE: Füllstandsmessung per Pegelsonde.

      @opossum said in Füllstandsmessung per Pegelsonde.:

      [EDIT:] Danke - es fehlt noch das Image von der Zisterne. Die Gauge-Widget sind besser als das jqplot. -> Hab eins gefunden

      Zisterne.png
      Auch sehr schön - für die Sektoren kann ich jetzt schön über bindings die Grenzen aus meinen mqtt-states einstellen:

      zisterne.png

      und:
      zisterne1.png

      posted in Praktische Anwendungen (Showcase)
      L
      ltathome
    • RE: Füllstandsmessung per Pegelsonde.

      @opossum Darf ich nochmal fragen, woher ich die "tolle Zisterne" haben könnte?

      Ich habe mein Teil jetzt seit ein paar Tagen auch "produktiv" - ich habe aber am Code noch deutlich umgebaut, da ich mir die Möglichkeit schaffen wollte, über ein Relais bei Erreichen eines Minimums oder Maximums zu schalten (< Minimal: Umschalten auf Hauswasser, Bei > maximal zurückschalten auf Zisterne. Zwei unterschiedliche Werte, weil das sonst erstens "flattert" und es keinen Sinn macht, selbst bei nur "minimal" über Minimum wieder zurückzuschalten. Und weil ich dann schon mal dran war, habe ich das sowohl über einen Taster, als auch per mqtt realisiert. Ich kann also per Taster (PIN D2) und mqtt das Relais (PIN D3) umschalten zwischen Automatik, Hauswasser und Zisterne. Die Schwellwerte lassen sich ebenfalls per mqtt setzen. Jetzt muss ich nur noch an der Hauswasserpumpe an das Umschaltventil ran um das ans Relais anzuschließen - die bisherige Schwimmerumschaltung klappt nicht sauber - und vor allem muss ich für manuelle Eingriffe jedesmal in den Keller..
      image0.jpeg image1.jpeg image2.jpeg

      /*------------------------------------------------------------------------------------------------------------------------------------------------------------------
        Program:      Füllstandsmessung mit Pegelsonde
      
        Description:  Dieses Programm misst die analolge Spannung an einem Port, welche von einem Drucksensor
                      0-5m Meßhöhe und 4-20mA Stromschnittstelle erzeugt wird.
                      Voraussetzung ist ein Meßwandler, welcher die 24V Versorgungsspannung an
                      den Drucksensor liefert und 0-3,3V analoge Spannung ausgibt.
                      Dienste:
                      DHCP, wenn vorhanden, sonst wird eine feste IP mit 192.168.1.21 vergeben.
      
        Hardware:     Arduino Nano ATmega 328P
                      W5100 Netzwerk shield
                      LCD Display I2C HD44780
      
      				Pin-Ports:
      				A0 = Analog IN
      				A4 = SDA
      				A5 = SCL
      
      
        Date:         20191013
        Modified:     Initial Version 1.0
                      - DHCP error routine
      
                      20191017
                      - Fixed uptime_d
      
                      20191019
                      Version 1.1
                      - Dichte Berechnung hinzugefügt
                      Version 1.2
                      - LCD wechselt jetzt alle 30 Sek. zwischen Uptime und Analog Messwert
      
                      20191024
                      - Fixed MQTT uptime_d char array
      
                      20191028
                      Version 1.3
                      - MQTT Port definierbar
                      - MQTT User Password authentication
      
      				20200110
      				Version 1.4
      				- Array für die Beruhigung des Messwertes eingefügt
      
        Author:       Eisbaeeer, https://github.com/Eisbaeeer
      
        Author:       Ethernet part: W.A. Smith, http://startingelectronics.com
                      progress bar -  CC BY-SA 3.0 :  skywodd, https://www.carnetdumaker.net/articles/faire-une-barre-de-progression-avec-arduino-et-liquidcrystal/
      
        LICENSE: 		MIT License
      
        -------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
      // Include some libraries
      #include <Ethernet.h>
      #include <SPI.h>
      
      #include <Wire.h>
      #include <hd44780.h>                       // main hd44780 header
      #include <hd44780ioClass/hd44780_I2Cexp.h> // i2c expander i/o class header
      hd44780_I2Cexp lcd; // declare lcd object: auto locate & auto config expander chip
      #include <Wire.h>
      #include <LiquidCrystal_I2C.h>
      
      #define twenty_x_four // 4x20 display
      
      #ifdef twenty_x_four
      const int LCD_COLS = 20;
      const int LCD_ROWS = 4;
      const int LCD_NB_COLUMNS = 20;
      #endif
      
      #ifdef sixteen_x_four
      const int LCD_COLS = 16;
      const int LCD_ROWS = 4;
      const int LCD_NB_COLUMNS = 16;
      #endif
      
      #include "progress.h"
      
      
      #define MODE_PIN 2
      #define MODE_ZISTERNE 0
      #define MODE_HAUSWASSER 1
      #define MODE_AUTO 2
      #define MODE_COUNT 10
      bool setmode = false;
      const char *modes[] = {"Zisterne", "Hauswasser", "Auto"};
      int mode_count = MODE_COUNT;
      int mode = MODE_AUTO;
      int old_mode = MODE_AUTO;
      int pin_stat;
      int old_stat;
      
      #define VALVE_PIN 3
      #define VALVE_ZISTERNE LOW
      #define VALVE_HAUSWASSER HIGH
      int valve = VALVE_ZISTERNE;
      int new_valve = VALVE_ZISTERNE;
      int reason = 0;
      const char *valves[] = {"Zisterne", "Hauswasser"};
      const char *reasons[] = {"manuelle Steuerung", "Automatik voll", "Automatik leer"};
      
      // ##############################################################################################################################
      // ---- HIER die Anpassungen vornehmen ----
      // ##############################################################################################################################
      // Hier die maximale Füllmenge des Behälters angeben. Dies gilt nur für symmetrische Behälter.
      const float max_liter = 6500;
      // Analoger Wert bei maximalem Füllstand (wird alle 30 Sekungen auf dem LCD angezeigt oder in der seriellen Konsole mit 9600 Baud.
      const int analog_max = 715;
      
      // Dichte der Flüssigkeit - Bei Heizöl bitte "1.086" eintragen, aber nur wenn die Kalibrierung mit Wasser erfolgt ist!
      // Bei Kalibrierung mit Wasser bitte "1.0" eintragen
      const float dichte = 1.0;
      
      // IP Adresse und Port des MQTT Servers
      const char *mqttserver = "iobroker.server.intern";
      const int mqttport = 1883;
      // Wenn der MQTT Server eine Authentifizierung verlangt, bitte folgende Zeile aktivieren und Benutzer / Passwort eintragen
      const char *mqttuser = "mqttiobroker";
      const char *mqttpass = "passwort";
      
      // IP Adresse, falls kein DHCP vorhanden ist. Diese Adresse wird nur verwendet, wenn der DHCP-Server nicht erreichbar ist.
      IPAddress ip(192, 168, 1, 21);
      
      // MAC-Addresse bitte anpassen! Sollte auf dem Netzwerkmodul stehen. Ansonsten eine generieren.
      byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0x0A };
      
      char buf[40];
      
      // ##############################################################################################################################
      // AB hier nichts mehr ändern!
      // (Ausser ihr wisst, was ihr tut)
      // ##############################################################################################################################
      
      // #define USE_SERIAL  Serial
      
      // No more delay
      unsigned long startMillis;  // some global variables available anywhere in the program
      unsigned long hstartMillis;  // some global variables available anywhere in the program
      unsigned long currentMillis;
      const unsigned long sekunde = 1000;  // one seconds
      const unsigned long hsekunde = 500;  //Half second
      
      unsigned long pinMillis;
      unsigned long lastMillis = 0;
      
      int secs = 0, mins = 0, hours = 0, days = 0;
      char uptime[25];
      
      float percent;
      float liter;
      float limit_low = 500;
      float limit_high = 1000;
      boolean LCD_Page;
      
      // Analog IN
      int analogPin = A0;
      const int messungen = 60;     // Anzahl Messungen
      int myArray[messungen];       // Array für Messwerte
      float analog = 0.0;             // Durchschnittswert
      int pointer = 0;              // Pointer für Messung
      
      // MQTT global vars
      #include <PubSubClient.h>
      unsigned int send_interval = 10; // the sending interval of indications to the server, by default 10 seconds
      #define MQTT_KEEPALIVE 60;
      
      boolean mqttconnected = false;
      
      // MQTT definitions
      void MqttCallback(char *topic, byte *payload, unsigned int length);
      EthernetClient ethClient;
      PubSubClient mqttclient;
      // (mqttserver, mqttport, MqttCallback, ethClient);
      #define MQTT_ID "Zisterne"
      
      char pl[30];
      
      // Declare subs
      void Mqttpublish();
      
      void defaultEthernet(void) {
          Ethernet.begin(mac, ip);  // initialize Ethernet device
      }
      
      void Uptime() {
          secs++;
          secs = secs % 60;
          if (secs == 0) {
              mins++;
              mins = mins % 60;
              if (mins == 0) {
                  hours++;
                  hours = hours % 24;
                  if (hours == 0) {
                      days++;
                      days = days % 10000;   // Nach 9999 Tagen zurück auf 0 (das sind 27 Jahre....)
                  }
              }
          }
          sprintf(uptime, "%4dd %2dh %2dm", days, hours, mins);
        
          if (secs == 0) {        // Every Minute
              //USE_SERIAL.print(F("Uptime: "));
              //USE_SERIAL.println(uptime);
              // MQTT reconnect timeout
              //Mqttpublish();
          }
          if (secs % send_interval == 0) { // Alle 30 Sekunden
              LCD_Page = !LCD_Page;
              Mqttpublish();
              // MqttSub();
          }
          if (mins == 0 && secs == 0) {      // Jede Stunde
              //USE_SERIAL.println(F("ONE HOUR"));
          }
      }
      
      void ReadAnalog() {
          // read the analog value and build floating middle
          myArray[pointer++] = analogRead(analogPin);      // read the input pin
          // myArray[pointer++] = 352;
      
          pointer = pointer % messungen;
      
          // Werte aufaddieren
          for (int i = 0; i < messungen; i++) {
              analog = analog + myArray[i];
          }
          // Summe durch Anzahl - geglättet
          analog = analog / messungen;
      
          percent = min(100 * analog / analog_max, 100);
      
          float calc = max_liter / analog_max;    // calculate percent
          calc = calc * dichte;                     // calculate dichte
          liter = min(analog * calc, max_liter);    // calculate liter
      
          /* //USE_SERIAL.print(F("Analog: "));
          //USE_SERIAL.println(analog);
          //USE_SERIAL.print(F("Prozent: "));
          //USE_SERIAL.println(percent);
          //USE_SERIAL.print(F("Liter: "));
          //USE_SERIAL.println(liter);
          */
      }
      
      void setup() {
          // USE_SERIAL.begin(9600);       // for debugging
      
          /*--------------------------------------------------------------
             LCD init
            --------------------------------------------------------------*/
          lcd.init();
          int status;
          status = lcd.begin(LCD_COLS, LCD_ROWS);
          if (status) { // non zero status means it was unsuccesful
              status = -status; // convert negative status value to positive number
              // begin() failed so blink error code using the onboard LED if possible
              hd44780::fatalError(status); // does not return
          }
        
          // initalization was successful, the backlight should be on now
          // Print a message to the LCD
          lcd.print("Zisterne");
          lcd.setCursor(0, 1);
          lcd.print("Version 1.4");
          lcd.setCursor(0, 3);
          lcd.print("github/Eisbaeeer");
          delay(2000);
        
          setup_progressbar();
        
          /*--------------------------------------------------------------
             Milliseconds start
            --------------------------------------------------------------*/
          startMillis = millis();  //initial start time
        
          /*--------------------------------------------------------------
             Ethernet init
            --------------------------------------------------------------*/
          if (Ethernet.begin(mac) == 0) {
              //USE_SERIAL.println(F("Failed config using DHCP"));
              // DHCP not working, switch to static IP
              defaultEthernet();
              if (Ethernet.hardwareStatus() == EthernetNoHardware) {
                  //USE_SERIAL.println(F("Eth shield not found"));
              } else if (Ethernet.linkStatus() == LinkOFF) {
                  //USE_SERIAL.println(F("Eth cable not conn"));
              }
          }
      
          // USE_SERIAL.print(F("IP: "));
          // USE_SERIAL.println(Ethernet.localIP());
      
        
          // start MQTT client
          MqttConnect(mqttuser, mqttpass);  
        
          /*-------------------------------------------------------------------
           * Setup Pins for Valve and mode-setting
           */
          pinMode(MODE_PIN, INPUT_PULLUP);
          pinMode(VALVE_PIN, OUTPUT);
        
          pin_stat = old_stat = digitalRead(MODE_PIN);
      }
      
      void MqttConnect(char *user, char* pass) {
      
          mqttclient.setClient(ethClient);
          mqttclient.setServer(mqttserver, mqttport);
          mqttclient.setCallback(MqttCallback);
          
          mqttconnected = mqttclient.connect(MQTT_ID, user, pass);
          if (mqttconnected) {
              // USE_SERIAL.println("Connected to Mqtt-Server");
              mqttclient.subscribe("Zisterne/cmd/Mode");
              mqttclient.subscribe("Zisterne/cmd/Limit");
              // USE_SERIAL.println("subscribing to Zisterne/cmd/Mode");
          }
      }
      
      void MqttCallback(char *topic, byte *payload, unsigned int length) {
          char *payloadvalue;
          char *payloadkey;
      
          payload[length] = '\0';
          payloadkey = (char *)&payload[0];
      
          // USE_SERIAL.println(payloadstring);
          if (strcmp(topic, "Zisterne/cmd/Mode") == 0) {
              if (strcmp(payloadkey, "0") == 0 || strcmp(payloadkey, "Zisterne") == 0) {
                  mode = MODE_ZISTERNE;
              } else if (strcmp(payloadkey, "1") == 0 || strcmp(payloadkey, "Hauswasser") == 0) {
                  mode = MODE_HAUSWASSER;
              } else if (strcmp(payloadkey, "2") == 0 || strcmp(payloadkey, "Auto") == 0) {
                  mode = MODE_AUTO;
              }
          } else if (strcmp(topic, "Zisterne/cmd/Limit") == 0) {
              int eq = 0;
              for (int i = 0; i < length; i++) {
                  if (payload[i] == '=') {
                      eq = i;
                      break;
                  }
              }
              if (eq > 0) {
                  payload[eq++] = 0;
                  payloadvalue = (char *)&payload[eq];
                  if (strcmp((char *)payload, "Low") == 0 || strcmp((char *)payload, "low") == 0) {
                      limit_low = atoi(payloadvalue);
                  }
                  if (strcmp((char *)payload, "High") == 0 || strcmp((char *)payload, "high") == 0) {
                      limit_high = atoi(payloadvalue);
                  }
              }
          }
      }
      
      void CheckEthernet() {
          if (Ethernet.hardwareStatus() != EthernetNoHardware) {
              /*--------------------------------------------------------------
                 check ehternet services
                --------------------------------------------------------------*/
              switch (Ethernet.maintain()) {
                  case 1:
                      //renewed fail
                      //USE_SERIAL.println(F("Error: renewed fail"));
                      break;
          
                  case 2:
                      //renewed success
                      //USE_SERIAL.println(F("Renewed success"));
                      //print your local IP address:
                      //USE_SERIAL.print(F("My IP address: "));
                      //USE_SERIAL.println(Ethernet.localIP());
                      break;
              
                  case 3:
                      //rebind fail
                      //USE_SERIAL.println(F("Error: rebind fail"));
                      break; 
          
                  case 4:
                      //rebind success
                      //USE_SERIAL.println(F("Rebind success"));
                      //print your local IP address:
                      //USE_SERIAL.print(F("My IP address: "));
                      //USE_SERIAL.println(Ethernet.localIP());
                      break;
              
                  default:
                      //nothing happened
                      break;
              }    
          }
      }
      
      void loop() {
          /*--------------------------------------------------------------
           remove delay (half second)
           --------------------------------------------------------------*/
          mqttclient.loop();
        
          pin_stat = digitalRead(MODE_PIN);
          pinMillis = millis();
          if (pin_stat == LOW) {
              if (pinMillis - lastMillis > 200) {
                  //USE_SERIAL.println("Impuls Low");
                  lastMillis = pinMillis;
                  mode_count = MODE_COUNT;
                  if (!setmode) {
                      setmode = true;
                      old_mode = mode;
                      //sprintf(buf, "Enter Settings-Mode %d (%s)", mode, modes[mode]);
                      //USE_SERIAL.println(buf);
                  } else {
                      mode--;
                      if (mode < 0) {
                          mode = 2;
                      }
                      //sprintf(buf, "Mode change to %d (%s)", mode, modes[mode]);
                      //USE_SERIAL.println(buf);
                  }
              }
          }
      
          /*--------------------------------------------------------------
           remove delay (one second)
           --------------------------------------------------------------*/
          currentMillis = millis();  //get the current "time" (actually the number of milliseconds since the program started)
          if (currentMillis - startMillis >= sekunde) { // Hier eine Sekunde warten
              startMillis = currentMillis;
              /******************************************************************************************
                 1 Sekunden Takt
               *****************************************************************************************/
              // Hier die Funktionen im Sekundentakt
              // ###################################
      
              CheckEthernet();
              Uptime();
              ReadAnalog();
              
              if (setmode) {
                  mode_count--;
                  if (mode_count <= 0) {
                      //sprintf(buf, "leaving Settings-Mode - change from %d to %d (%s)", old_mode, mode, modes[mode]);
                      //USE_SERIAL.println(buf);
                      old_mode = mode;
                      setmode = false;
                  }
              }
              if (!setmode) {
                  if (mode == MODE_ZISTERNE) {
                      new_valve = VALVE_ZISTERNE;
                      reason = 0;
                  } else if (mode == MODE_HAUSWASSER) {
                      new_valve = VALVE_HAUSWASSER;
                      reason = 0;
                  } else if (mode == MODE_AUTO) {
                      if (liter >= limit_high) {
                          new_valve = VALVE_ZISTERNE;
                          reason = 1;
                      }
                      if (liter <= limit_low) {
                          new_valve = VALVE_HAUSWASSER;
                          reason = 2;
                      }
                  }
              }
              /*-----------------------------------------------------------
               * Wenn Ventil umzuschalten ist
              */
              if (new_valve != valve) {
                  valve = new_valve;
                  digitalWrite(VALVE_PIN, valve);
                  //sprintf(buf, "Set Valve to %s (%s)", valves[valve], reasons[reason]);
                  //USE_SERIAL.println(buf);
              }
          
              // print out to LCD
      
              if (!setmode) {
                  draw_progressbar(percent);
              }
              write_lcd();
          }
      
      }
      /******************************************************************************************
         Ende Loop
      * ****************************************************************************************
         Beginn Unterprogramme
      ******************************************************************************************/
      
      void write_lcd(void) {
          char LCDbuff[20];
      
          if (!setmode) {
          // Zeile 1
              lcd.setCursor(6, 0);
              dtostrf(liter, 4, 0, LCDbuff);
              lcd.print(LCDbuff); lcd.print(" Liter");
      
      
      #ifdef sixteen_x_four
              if ( LCD_Page == false ) {
                  // Zeile 3
                  lcd.setCursor(0, 2);
                  lcd.print("Uptime");
      
                  // Zeile 4
                  lcd.setCursor(0, 3);
                  lcd.print(uptime);
              } else {
                  // Zeile 3
                  lcd.setCursor(0, 2);
                  lcd.print("Messwert Analog");
              
                  // Zeile 4
                  lcd.setCursor(0, 3);
                  lcd.print(analogRead(analogPin));      
              }
      #endif
      #ifdef twenty_x_four
              // Zeile 3
              lcd.setCursor(0, 2);
              lcd.print("Uptime");
            
              // Zeile 3
              lcd.setCursor(7, 2);
              lcd.print(uptime);
            
              // Zeile 4
              lcd.setCursor(0, 3);
              if (mode == 2) {
                  lcd.print("Auto: ");
              } else {
                  lcd.print("Manuell: ");
              }
              lcd.setCursor(10, 3);
              lcd.print(valves[valve]);
            
              // Zeile 4
              // lcd.setCursor(16, 3);
              // lcd.print(analogRead(analogPin));
      #endif
          } else {
              lcd.clear();
              lcd.setCursor(0, 0);
              lcd.print("Ventilsteuerung     ");
              lcd.setCursor(0, 1);
              lcd.print("Bisher: ");
              lcd.setCursor(10, 1);
              lcd.print(modes[old_mode]);
              lcd.print("       ");
              lcd.setCursor(0, 2);
              lcd.print("Neu: ");
              lcd.setCursor(6, 2);
              lcd.print(modes[mode]);
              lcd.setCursor(0, 3);
              lcd.print(mode_count);
          }
      }
      
      void Mqttpublish(void) {
          if (mqttclient.connected()) {
              dtostrf(analog, 5, 2, buf);
              mqttclient.publish("Zisterne/Analog", buf);
              dtostrf(liter, 5, 0, buf);
              mqttclient.publish("Zisterne/Liter", buf);
              dtostrf(limit_low, 1, 0, buf);
              mqttclient.publish("Zisterne/LiterLow", buf);
              dtostrf(limit_high, 1, 0, buf);
              mqttclient.publish("Zisterne/LiterHigh", buf);
              dtostrf(percent, 5, 0, buf);
              mqttclient.publish("Zisterne/Prozent", buf);
              
              if (mode == 2) {
                  mqttclient.publish("Zisterne/Modus", "Auto");
              } else {
                  mqttclient.publish("Zisterne/Modus", "Manuell");          
              }
              dtostrf(mode, 1, 0, buf);
              mqttclient.publish("Zisterne/Mode", buf);
              dtostrf(valve, 1, 0, buf);
              mqttclient.publish("Zisterne/Valve", buf);
              mqttclient.publish("Zisterne/Ventil", valves[valve]);
      
              // System
              mqttclient.publish("Zisterne/Uptime", uptime);
          } else {
              MqttConnect(mqttuser, mqttpass);  
          }
      }
      
      void draw_progressbar(byte percent) {
        
          lcd.clear();
          /* Affiche la nouvelle valeur sous forme numérique sur la première ligne */
          lcd.setCursor(0, 0);
          lcd.print(percent);
          lcd.print(F(" %  "));
          // N.B. Les deux espaces en fin de ligne permettent d'effacer les chiffres du pourcentage
          // précédent quand on passe d'une valeur à deux ou trois chiffres à une valeur à deux ou un chiffres.
        
          /* Déplace le curseur sur la seconde ligne */
          lcd.setCursor(0, 1);
        
          /* Map la plage (0 ~ 100) vers la plage (0 ~ LCD_NB_COLUMNS * 2 - 2) */
          byte nb_columns = map(percent, 0, 100, 0, LCD_NB_COLUMNS * 2 - 2);
          // Chaque caractère affiche 2 barres verticales, mais le premier et dernier caractère n'en affiche qu'une.
        
          /* Dessine chaque caractère de la ligne */
          for (byte i = 0; i < LCD_NB_COLUMNS; ++i) {
              if (i == 0) { // Premiére case
                  /* Affiche le char de début en fonction du nombre de colonnes */
                  if (nb_columns > 0) {
                      lcd.write(1); // Char début 1 / 1
                      nb_columns -= 1;      
                  } else {
                      lcd.write((byte) 0); // Char début 0 / 1
                  }    
              } else if (i == LCD_NB_COLUMNS - 1) { // Derniére case    
                  /* Affiche le char de fin en fonction du nombre de colonnes */
                  if (nb_columns > 0) {
                      lcd.write(6); // Char fin 1 / 1    
                  } else {
                      lcd.write(5); // Char fin 0 / 1
                  }  
              } else { // Autres cases
                  /* Affiche le char adéquat en fonction du nombre de colonnes */
                  if (nb_columns >= 2) {
                      lcd.write(4); // Char div 2 / 2
                      nb_columns -= 2;
                  } else if (nb_columns == 1) {
                      lcd.write(3); // Char div 1 / 2
                      nb_columns -= 1;
                  } else {
                      lcd.write(2); // Char div 0 / 2
                  }
              }
          }
      }
      
      posted in Praktische Anwendungen (Showcase)
      L
      ltathome
    • RE: Füllstandsmessung per Pegelsonde.

      Soderle - morgen oder Sonntag - wenn das Wetter mitspielt, kalibriere ich das Teil mit voller Zisterne.

      Im Code ist das maximale Volumen hinterlegt - das wird bei maximalem analogen Wert erreicht - soweit klar.
      Zwei Fragen:

      1. Gemäß Spez. kann der Nano 5V am Analogen Eingang - ich würde das Poti für den maximalen Wert also auf "Knapp drunter" einstellen, wenn die Sonde bei voller Zisterne ganz unten ist. Der Analoge Maximalwert müsste doch dann recht dicht an 1023 sein und nicht rund 25% niedriger (wie im Code) oder?
      2. Im Code wird der Prozentsatz aus dem analogen Wert ermittelt, indem mit 0,132 multipliziert wird und dann auf 100 gekappt. Das erschliest sich mir nicht. Der Prozentsatz x ist doch:

      x = 100% / maximaler Analoger Wert * analoger Messwert

      oder habe ich einen denkfehler?

      Und wo bekomme ich die schöne Visualisierung aus dem Thread weiter oben her?

      Warum ist der maximale Wert nicht per se bei 1023?
      Das müsste doch der gewünschte wert für eine maximale Auflösung sein und dem maximalen
      EDIT: nachdem ich heute kalibriert hab und nur auf 1,4V kam, habe ich mir die Mühe gemacht und den ganzen Thread nochmal gelesen..
      Ich habs jetzt auch verstanden:

      1. den maximalen Wert erreicht man nur, wenn die Sonde auch die volle Nenntiefe versenkt ist - logisch - bei ner 5m Sonde und 2,50 max Tiefe (6,5cbm - Zisterne) passiert das nie.
      2. Die 5v-Story stehen ebenfalls im Thread weiter vorne - sowei auch das geklät - ich werde morgen nochmal mit beiden Jumpern gesteckt testen - dann müsste ich deutlich dichter an die 5V

      Nur das Thema Multiplikation mit 0,132 leuchtet mir immer noch nicht ein.

      posted in Praktische Anwendungen (Showcase)
      L
      ltathome
    • RE: Füllstandsmessung per Pegelsonde.

      Das wäre die Version mit den Anpassungen (jetzt korrigiert):

      Zisterne.ino

      posted in Praktische Anwendungen (Showcase)
      L
      ltathome
    • RE: Füllstandsmessung per Pegelsonde.

      @Eisbaeeer said in Füllstandsmessung per Pegelsonde.:
      na dann ....

      Ich hätte den Code für 4x20 fertig. Ich sehe da noch ein Problem - aber vllt. liegt das auch an meiner Unwissenheit....

      Ich habe dein Repo gecloned, in der IDE Zisterne.ino geöffnet - und dann mosert die IDE, dass sie gerne ein Verzeichnis "Zisterne" hätte, legt das Verzeichnis an und schiebt das File darein, der anschließende Compile mosert dann über ein fehlendes progress.h, was ich dadurch gelöst habe, dass ich das ebenfalls in den Ordner "zisterne" verschoben habe.

      Dies nur als Vorwarnung - welchen Button meinst du? was ist jetzt das korrekte vorgehen? und sollen wir das "irgendwie" per Chat lösen? wir spammen hier den Thread voll....

      posted in Praktische Anwendungen (Showcase)
      L
      ltathome
    Community
    Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen
    The ioBroker Community 2014-2023
    logo