Navigation

    Logo
    • Register
    • Login
    • Search
    • Recent
    • Tags
    • Unread
    • Categories
    • Unreplied
    • Popular
    • GitHub
    • Docu
    • Hilfe
    1. Home
    2. Deutsch
    3. Skripten / Logik
    4. [gelöst] (vorübergehend) Luftgütesensor BME 680

    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

    [gelöst] (vorübergehend) Luftgütesensor BME 680

    This topic has been deleted. Only users with topic management privileges can see it.
    • Chaot
      Chaot last edited by

      Hi,

      vielleicht kann mir jemand mal weiterhelfen.

      Vielleicht ist meine Idee ja auch Quatsch und ich lasse das auch wieder….

      Ich habe über Aliexpress einen kleinen Luftgütesensor bezogen. Das Ding nennt sich BME680. Ich wollte absichtlich ein Teil das nicht "nur" CO2 misst sondern etwas Breitbandiger ist. Dazu sollte es möglichst klein sein weil ich es in ein unauffälliges Gehäuse an der Decke platzieren möchte. Bei einem größeren Gehäuse reißt mir meine Frau lebenswichtige Teile ab :oops:

      Ich habe das Teil jetzt an einem Sonoff SV mit Tasmota Firmware angeschlossen und arbeite mich seit mehreren Tagen durch Datenblätter und alle möglichen Informationen. Bosch scheint ja aus der Umrechnung ein Staatsgeheimnis zu machen.

      Die Umrechnung schein so zu laufen:

      Luftqualität besser: Widerstand höher

      Luftqualität schlechter Widerstand geringer

      Setup:

      Widerstandswert nach 5 Minuten klare Luft als Basis

      Luftfeuchtigkeit 50% als Basis

      Gewichtung Gas/Luftfeuchte 75/25

      Dazu habe ich zwar ein paar scripte gefunden, aber kann ich die Im ioBroker so einbinden?

      Version 1:

      #!/usr/bin/env python
      
      import bme680
      import time
      
      print("""Estimate indoor air quality
      Runs the sensor for a burn-in period, then uses a 
      combination of relative humidity and gas resistance
      to estimate indoor air quality as a percentage.
      Press Ctrl+C to exit
      """)
      
      sensor = bme680.BME680()
      
      # These oversampling settings can be tweaked to 
      # change the balance between accuracy and noise in
      # the data.
      
      sensor.set_humidity_oversample(bme680.OS_2X)
      sensor.set_pressure_oversample(bme680.OS_4X)
      sensor.set_temperature_oversample(bme680.OS_8X)
      sensor.set_filter(bme680.FILTER_SIZE_3)
      sensor.set_gas_status(bme680.ENABLE_GAS_MEAS)
      
      sensor.set_gas_heater_temperature(320)
      sensor.set_gas_heater_duration(150)
      sensor.select_gas_heater_profile(0)
      
      # start_time and curr_time ensure that the 
      # burn_in_time (in seconds) is kept track of.
      
      start_time = time.time()
      curr_time = time.time()
      burn_in_time = 300
      
      burn_in_data = []
      
      try:
          # Collect gas resistance burn-in values, then use the average
          # of the last 50 values to set the upper limit for calculating
          # gas_baseline.
          print("Collecting gas resistance burn-in data for 5 mins\n")
          while curr_time - start_time < burn_in_time:
              curr_time = time.time()
              if sensor.get_sensor_data() and sensor.data.heat_stable:
                  gas = sensor.data.gas_resistance
                  burn_in_data.append(gas)
                  print("Gas: {0} Ohms".format(gas))
                  time.sleep(1)
      
          gas_baseline = sum(burn_in_data[-50:]) / 50.0
      
          # Set the humidity baseline to 40%, an optimal indoor humidity.
          hum_baseline = 40.0
      
          # This sets the balance between humidity and gas reading in the 
          # calculation of air_quality_score (25:75, humidity:gas)
          hum_weighting = 0.25
      
          print("Gas baseline: {0} Ohms, humidity baseline: {1:.2f} %RH\n".format(gas_baseline, hum_baseline))
      
          while True:
              if sensor.get_sensor_data() and sensor.data.heat_stable:
                  gas = sensor.data.gas_resistance
                  gas_offset = gas_baseline - gas
      
                  hum = sensor.data.humidity
                  hum_offset = hum - hum_baseline
      
                  # Calculate hum_score as the distance from the hum_baseline.
                  if hum_offset > 0:
                      hum_score = (100 - hum_baseline - hum_offset) / (100 - hum_baseline) * (hum_weighting * 100)
      
                  else:
                      hum_score = (hum_baseline + hum_offset) / hum_baseline * (hum_weighting * 100)
      
                  # Calculate gas_score as the distance from the gas_baseline.
                  if gas_offset > 0:
                      gas_score = (gas / gas_baseline) * (100 - (hum_weighting * 100))
      
                  else:
                      gas_score = 100 - (hum_weighting * 100)
      
                  # Calculate air_quality_score. 
                  air_quality_score = hum_score + gas_score
      
                  print("Gas: {0:.2f} Ohms,humidity: {1:.2f} %RH,air quality: {2:.2f}".format(gas, hum, air_quality_score))
                  time.sleep(1)
      
      except KeyboardInterrupt:
          pass
      
      ````Quelle: [https://github.com/pimoroni/bme680/blob … quality.py](https://github.com/pimoroni/bme680/blob/master/examples/indoor-air-quality.py)
      
      Version 2:
      
      

      /***************************************************************************
      This is a library for the BME680 gas, humidity, temperature & pressure sensor
      Designed specifically to work with the Adafruit BME680 Breakout
      ----> http://www.adafruit.com/products/XXXX
      These sensors use I2C or SPI to communicate, 2 or 4 pins are required
      to interface.
      Adafruit invests time and resources providing this open source code,
      please support Adafruit andopen-source hardware by purchasing products
      from Adafruit!
      Written by Limor Fried & Kevin Townsend for Adafruit Industries.
      BSD license, all text above must be included in any redistribution
      ***************************************************************************/

      #include <wire.h>
      #include <spi.h>
      #include <adafruit_sensor.h>
      #include "Adafruit_BME680.h"

      #define BME_SCK 13
      #define BME_MISO 12
      #define BME_MOSI 11
      #define BME_CS 10
      #define SEALEVELPRESSURE_HPA (1013.25)

      Adafruit_BME680 bme; // I2C
      //Adafruit_BME680 bme(BME_CS); // hardware SPI
      //Adafruit_BME680 bme(BME_CS, BME_MOSI, BME_MISO, BME_SCK);

      float hum_weighting = 0.25; // so hum effect is 25% of the total air quality score
      float gas_weighting = 0.75; // so gas effect is 75% of the total air quality score

      float hum_score, gas_score;
      float gas_reference = 250000;
      float hum_reference = 40;
      int getgasreference_count = 0;

      void setup() {
      Serial.begin(115200);
      while (!Serial);
      Serial.println(F("BME680 test"));

      Wire.begin();
      if (!bme.begin()) {
      Serial.println("Could not find a valid BME680 sensor, check wiring!");
      while (1);
      } else Serial.println("Found a sensor");

      // Set up oversampling and filter initialization
      bme.setTemperatureOversampling(BME680_OS_2X);
      bme.setHumidityOversampling(BME680_OS_2X);
      bme.setPressureOversampling(BME680_OS_2X);
      bme.setIIRFilterSize(BME680_FILTER_SIZE_3);
      bme.setGasHeater(320, 150); // 320°C for 150 ms
      // Now run the sensor for a burn-in period, then use combination of relative humidity and gas resistance to estimate indoor air quality as a percentage.
      GetGasReference();
      }

      void loop() {
      Serial.print("Temperature = ");

      Serial.print(bme.readTemperature());
      Serial.println("°C");

      Serial.print(" Pressure = ");

      Serial.print(bme.readPressure() / 100.0F);
      Serial.println(" hPa");

      Serial.print(" Humidity = ");
      Serial.print(bme.readHumidity());
      Serial.println("%");

      Serial.print(" Gas = ");
      Serial.print(bme.readGas());
      Serial.println("R\n");
      /*
      This software, the ideas and concepts is Copyright (c) David Bird 2018. All rights to this software are reserved.

      Any redistribution or reproduction of any part or all of the contents in any form is prohibited other than the following:
      1. You may print or download to a local hard disk extracts for your personal and non-commercial use only.
      2. You may copy the content to individual third parties for their personal use, but only if you acknowledge the author David Bird as the source of the material.
      3. You may not, except with my express written permission, distribute or commercially exploit the content.
      4. You may not transmit it or store it in any other website or other form of electronic retrieval system for commercial purposes.
      The above copyright ('as annotated') notice and this permission notice shall be included in all copies or substantial portions of the Software and where the
      software use is visible to an end-user.

      THE SOFTWARE IS PROVIDED "AS IS" FOR PRIVATE USE ONLY, IT IS NOT FOR COMMERCIAL USE IN WHOLE OR PART OR CONCEPT. FOR PERSONAL USE IT IS SUPPLIED WITHOUT WARRANTY
      OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
      IN NO EVENT SHALL THE AUTHOR OR COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
      See more at http://www.dsbird.org.uk
      /
      //Calculate humidity contribution to IAQ index
      float current_humidity = bme.readHumidity();
      if (current_humidity >= 38 && current_humidity <= 42)
      hum_score = 0.25
      100; // Humidity +/-5% around optimum
      else
      { //sub-optimal
      if (current_humidity < 38)
      hum_score = 0.25/hum_referencecurrent_humidity100;
      else
      {
      hum_score = ((-0.25/(100-hum_reference)*current_humidity)+0.416666)*100;
      }
      }

      //Calculate gas contribution to IAQ index
      int gas_lower_limit = 5000; // Bad air quality limit
      int gas_upper_limit = 50000; // Good air quality limit
      if (gas_reference > gas_upper_limit) gas_reference = gas_upper_limit;
      if (gas_reference < gas_lower_limit) gas_reference = gas_lower_limit;
      gas_score = (0.75/(gas_upper_limit-gas_lower_limit)gas_reference -(gas_lower_limit(0.75/(gas_upper_limit-gas_lower_limit))))*100;

      //Combine results for the final IAQ index value (0-100% where 100% is good quality air)
      float air_quality_score = hum_score + gas_score;

      Serial.println("Air Quality = "+String(air_quality_score,1)+"% derived from 25% of Humidity reading and 75% of Gas reading - 100% is good quality air");
      Serial.println("Humidity element was : "+String(hum_score/100)+" of 0.25");
      Serial.println(" Gas element was : "+String(gas_score/100)+" of 0.75");
      if (bme.readGas() < 120000) Serial.println("***** Poor air quality *****");
      Serial.println();
      if ((getgasreference_count++)%10==0) GetGasReference();
      Serial.println(CalculateIAQ(air_quality_score));
      Serial.println("------------------------------------------------");
      delay(2000);
      }

      void GetGasReference(){
      // Now run the sensor for a burn-in period, then use combination of relative humidity and gas resistance to estimate indoor air quality as a percentage.
      Serial.println("Getting a new gas reference value");
      int readings = 10;
      for (int i = 0; i <= readings; i++){ // read gas for 10 x 0.150mS = 1.5secs
      gas_reference += bme.readGas();
      }
      gas_reference = gas_reference / readings;
      }

      String CalculateIAQ(float score){
      String IAQ_text = "Air quality is ";
      score = (100-score)*5;
      if (score >= 301) IAQ_text += "Hazardous";
      else if (score >= 201 && score <= 300 ) IAQ_text += "Very Unhealthy";
      else if (score >= 176 && score <= 200 ) IAQ_text += "Unhealthy";
      else if (score >= 151 && score <= 175 ) IAQ_text += "Unhealthy for Sensitive Groups";
      else if (score >= 51 && score <= 150 ) IAQ_text += "Moderate";
      else if (score >= 00 && score <= 50 ) IAQ_text += "Good";
      return IAQ_text;
      }</adafruit_sensor.h></spi.h></wire.h>

      
      Ich bekomme aus dem Sonoff die im Anhang aufgeführten Objekte geliefert
      
      Meine Umsetzung wäre jetzt eine durch ein Script einen Datenpunkt zu erzeugen der dann per VIS als Displayfläche dargestellt wird die die Farbe ändert.
      
      Ich habe mit scripten absolut wenig Erfahrung. Ich kann mir zwar manches zusammenreimen, aber so grundsätzliche Denkanstöße brauche ich immer dafür. Es wäre nett wenn mir jemand weiterhelfen könnte.
      
      Ich kann gerne auch aus der nächsten Lieferung einen BME680 als Belohnung spendieren. Die sind aber aktuell noch auf dem Postweg.
      [5779_bme680.jpg](/assets/uploads/files/5779_bme680.jpg)
      1 Reply Last reply Reply Quote 0
      • Chaot
        Chaot last edited by

        Ich habe mich jetzt mangels Javasript Kentnissen an Blockly versucht.

        Kann das funktionieren?

        Zunächst das Script getriggert auf Änderung des Gassensors und im zweiten Bild die beiden Formeln
        5779_luftgueteformel1.jpg
        5779_luftguete1.jpg

        1 Reply Last reply Reply Quote 0
        • Chaot
          Chaot last edited by

          Jetzt stellt sich eigentlich die Frage wie ich aus der Formel das Ergebnis in den Datenpunkt bekomme.

          Irgendwas übersehe ich da. Mir wird aktuell nur "true" reingeschrieben.

          1 Reply Last reply Reply Quote 0
          • Chaot
            Chaot last edited by

            Für heute reichts erstmal. Mir raucht der Kopf.

            Ich habe jetzt einen Wert der wie ein IAQ aussieht. Allerdings mit 8 Dezimalstellen. Das will ich noch ändern.

            Dazu habe ich noch eine Ausertung erstellt mit der ich dann ein Farbfeld steuern möchte.

            Allerdings habe ich das noch nicht getestet. Ich denke aber das das so nicht funktionieren wird.

            Wenn jemand Vorschläge hat oder das Ganze vereinfachen kann dann bitte her damit.
            5779_luftgueteauswertung.jpg
            5779_luftgueteb.jpg
            5779_luftguetea.jpg

            1 Reply Last reply Reply Quote 0
            • G
              Garf last edited by

              @Chaot:

              Ich habe über Aliexpress einen kleinen Luftgütesensor bezogen. Das Ding nennt sich BM680. `
              Mit deinem Beitrag hast Du mich wieder irgendwie angefixt und nun denke ich gerade darüber nach mir auch so ein Teil zu bestellen. Welchen hast Du bei Aliexpress bestellt?

              Der Fühler soll an die I2C Schnittstelle angeschlossen werden.

              Für mich kämen folgende Fühler in Frage:

              https://www.amazon.de/BlueDot-BME680-Se … I2C+BME680

              https://www.watterott.com/de/BME680-Breakout

              Wobei dieser mein Favorit wäre:

              https://de.aliexpress.com/item/DFRobot- … autifyAB=0

              1 Reply Last reply Reply Quote 0
              • Chaot
                Chaot last edited by

                Ich wollte recht klein:

                https://de.aliexpress.com/item/BME680-D … 4c4djehDSC

                Allerdings habe ich das Script immer noch nicht so richtig am laufen.

                Irgendwie scheint auch die Formel in der Form nicht zu stimmen.

                Wenn ich die Luft "verunreinige" (Taschentuch mit Alkohol) sinkt bei mir der gelesene Widerstandswert. Also genau umgekehrt zur Formel.

                Da werde ich mir das am Wochenende mal genauer anschauen müssen.

                1 Reply Last reply Reply Quote 0
                • G
                  Garf last edited by

                  @Chaot:

                  Ich wollte recht klein: ` Und wie eingebunden, I²C- oder SPI-Bus?

                  > Da werde ich mir das am Wochenende mal genauer anschauen müssen.
                  Immer gut wenn sich schon jemand in das Thema reinhängt. :mrgreen:

                  Ich werde dann mal meinen Favoriten bestellen.

                  1 Reply Last reply Reply Quote 0
                  • Chaot
                    Chaot last edited by

                    Das hängt an einem Sonoff SV mit Tasmota Firmware und ist dort über I²C Bus eingebunden.

                    Die Daten werden per MQTT an den ioBroker gesendet und dort dann per Script (hoffentlich irgendwann einmal) weiterverarbeitet um dann in VIS als mehrfarbige Fläche (Ampel) dargestellt zu werden.

                    Das Projekt ist jetzt gerade eine Woche alt, aber ich bin mit Scripten nicht so 100% fit das ich wirklich lange grübeln muss wie ich was umsetzen kann.

                    Auch für Blockly (obwohl im Grunde einfach) bin ich wohl etwas alt.

                    1 Reply Last reply Reply Quote 0
                    • Chaot
                      Chaot last edited by

                      Nach ein paar Tagen herumexperimentieren habe ich den Eindruck gewonnen das mit der Tasmota Firmware irgendwas nicht stimmen kann.

                      1. Mein Sensor verhält sich genau umgekehrt zur Beschreibung. Lege ich einen Lappen mit Spiritus neben den Sensor geht der Wert auf 9 kOhm RUNTER! Laut Bosch sollte der Wert nach oben gehen.

                      2. Im Datenblatt wird eine Heiz- und Ausleseperiode beschrieben. Das kann ich an den gelieferten Werten nicht erkennen. Ich sehe einen ständig schwankenden Widerstandswert der offensichtlich einfach nur ausgelesen wird ohne einen Messrhythmus zu befolgen.

                      3. Wenn ich die Weboberfläche des Sensors offen lasse steigt der Widerstandswert ständig an ohne das sich an der Luft etwas verändern würde.

                      Von daher habe ich meine Experimente mit dem Script zunächst zurückgestellt bis ich herausgefunden habe was hier falsch läuft.

                      1 Reply Last reply Reply Quote 0
                      • Chaot
                        Chaot last edited by

                        Jetz wird es schräg.

                        Da mir derzeit keine bessere Lösung einfällt und Bosch offensichtlich die Formeln geheim hält werde ich langfristig vermutlich nicht beim BME680 bleiben.

                        Übergangsweise habe ich mir eine Lösung gebastelt die Meine Zwecke erfüllen müsste:

                        Aus dem angehängten Tabellenblatt (von adafruit) habe ich mir folgende Formel konstruiert:

                        Basistemperatur: 21°C
                        Basisluftfeuchte: 40%
                        Basiswert: 5 kOhm
                        
                        Wichtung:
                        Temperatur: 4,7%
                        Luftfeuchte: 8%
                        Luftgüte: 70%
                        
                        A= Temperatur
                        B= Luftfeuchte
                        C= Widerstandswert in kOhm
                        
                        ((100-21-A)/(100-21)*(0,047*100))+((100-40-B)/(100-40)*(0,08*100))+((C/5)*(0,7*10))
                        

                        Da hier aber die Werte jetzt noch auf IAQ angepasst werden sollten habe ich die Werte etwas verschoben damit ich bei ca. 500 ende:

                        ((79-A)/(79*3,3))+((60-B)/(60*5,6))+((C/5)*4,9)
                        oder
                        ((79-A)/260,7)+((60-B)/336)+((C/5)*4,9)
                        

                        Da jetzt die Werte offensichtlich nicht der gängigen IAQ Tabelle entsprechen habe ich meine Grenzwerte entsprechend angepasst.

                        Da ich hier mit recht wenig Umweltverschmutzung lebe habe ich den Grenzwert "offenes Fenster neben Sensor" als Übergangswert zur "normalen" Luftqualität angelegt.

                        Somit habe ich dann für AIQ folgende Grenzwerte:

                        500 - 301 Sehr gut

                        300 - 251 Normal

                        200 - 151 etwas Schlecht

                        150 - 101 Schlecht

                        100 - 51 sehr schlecht

                        50 - 0 Extrem schlecht

                        Ich denke mit dem Kompromiss kann ich aktuell arbeiten und suche jetzt einen Sensor der nicht "Top Secret" ist.

                        Falls mir jemand noch bei der Umsetzung in VIS helfen könnte wäre ich recht dankbar.

                        Ich dachte an ein farbig hinterlegtes Feld das den Wert anzeigt und entsprechend die Farbe ändert. Leider habe ich keine Ahnung welches Widget oder welche Kombination dazu geeignet wäre.
                        5779_slide1.jpg

                        1 Reply Last reply Reply Quote 0
                        • Chaot
                          Chaot last edited by

                          So, dank tatkräftiger Hilfe von Paul53 habe ich es geschafft eine Anzeigefläche in VIS zu basteln.

                          Das Script für die Auswertung:

                          const Luftguete = "javascript.1.Luftguete"/*Luftguete*/;
                          
                          function setQualitaet(x) { 
                            var y = 0;
                            if(x > 50) y = 1;
                            if(x > 100) y = 2;
                            if(x > 150) y = 3;
                            if(x > 200) y = 4;
                            if(x > 300) y = 5;
                            setState("javascript.1.Luftqualität"/*Luftqualität*/, y, true);
                          }
                          
                          setQualitaet(getState(Luftguete).val); // Skriptstart
                          
                          on(Luftguete, function(dp) { // triggert bei Wertänderung
                            setQualitaet(dp.state.val);
                          });
                          

                          Schreibt einen Datenpunkt "Luftqualität" in das Objekt Javasript.1.

                          In VIS nehme ich nun ein "Image 8" und frage dort den Wert des Datenpunkts ab.

                          Als Bilder verwende ich einfach 100x100 Bilder mit entsprechender Hintergrundfarbe. Optional wären auch Smilies denkbar.

                          Ich danke erst mal allen die sich auch Gedanken zu dem Thema gemacht haben und hoffe das meine vorübergehende Lösung für die ersten Schritte mit dem BME680 taugt.

                          Wenn das jemand nachbauen möchte darf er sich das gerne mitnehmen.

                          Das Erfassungssscript

                          on({id: 'sonoff.0.Umweltsensor.BME680_Gas', change: "ne"}, function (obj) {
                            var value = obj.state.val;
                            var oldValue = obj.oldState.val;
                            setState("javascript.1.Luftguete"/*Luftguete*/, ((79 - getState("sonoff.0.Umweltsensor.BME680_Temperature").val) / 260.7 + (60 - getState("sonoff.0.Umweltsensor.BME680_Humidity").val) / 336 + (getState("sonoff.0.Umweltsensor.BME680_Gas").val / 5) * 4.9), true);
                          });
                          
                          

                          Noch ein Hinweis: Alle beiden scripte laufen in der Instanz javascript.1. Bei einer Übernahme muss das eventuell an die eigene Situation angepasst werden.

                          G 1 Reply Last reply Reply Quote 0
                          • G
                            gutgut30 @Chaot last edited by

                            @Chaot
                            Besten Dank für das Teilen deines Scriptes.

                            Als Tipp für Newbies die evtl. genau so fragend vor dem PC sitzen und sich wundern warum immer nur 100 als Wert erscheint:
                            Ihr müsst den Zahlenbereich des angelegten Datenpunktes "Luftguete" entsprechend anpassen 😉

                            1 Reply Last reply Reply Quote 0
                            • First post
                              Last post

                            Support us

                            ioBroker
                            Community Adapters
                            Donate

                            807
                            Online

                            31.9k
                            Users

                            80.2k
                            Topics

                            1.3m
                            Posts

                            3
                            12
                            6447
                            Loading More Posts
                            • Oldest to Newest
                            • Newest to Oldest
                            • Most Votes
                            Reply
                            • Reply as topic
                            Log in to reply
                            Community
                            Impressum | Datenschutz-Bestimmungen | Nutzungsbedingungen
                            The ioBroker Community 2014-2023
                            logo