MagicMirror Forum
    • Recent
    • Tags
    • Unsolved
    • Solved
    • MagicMirror² Repository
    • Documentation
    • 3rd-Party-Modules
    • Donate
    • Discord
    • Register
    • Login
    A New Chapter for MagicMirror: The Community Takes the Lead
    Read the statement by Michael Teeuw here.

    AHT20 Humidity + Temperature Sensor

    Scheduled Pinned Locked Moved Solved Requests
    18 Posts 3 Posters 1.1k Views 3 Watching
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • S Offline
      sdetweil @JohnGalt
      last edited by

      @JohnGalt the module also has a node_helper.js , this is where the python script is launched

      browsers cannot access hardware or files directly (for security reasons)

      Sam

      How to add modules

      learning how to use browser developers window for css changes

      J 1 Reply Last reply Reply Quote 0
      • J Offline
        JohnGalt @sdetweil
        last edited by

        @sdetweil – Hi Sam, thanks for looking in on this.

        I guess I don’t understand… If the module is calling a python script, and the script is polling the sensor - then it would seem to me that the browser isn’t accessing the hardware or files directly. Obviously I’m missing something here.

        S 1 Reply Last reply Reply Quote 0
        • S Offline
          sdetweil @JohnGalt
          last edited by

          @JohnGalt the browser (electron) wants to display the data from the sensor, but it cant read it directly. so the module sends a request to the helper to get the data from device 0x38

          the module uses a python script to get the data
          the python script is reporting an error

          that is what needs to be looked at.

          you posted the code from the module/browser side which is not involved in getting the actual data

          Sam

          How to add modules

          learning how to use browser developers window for css changes

          J 1 Reply Last reply Reply Quote 0
          • R Offline
            rkorell @JohnGalt
            last edited by rkorell

            the python script you are looking for is bme280.py

            #!/usr/bin/python
            #--------------------------------------
            #    ___  ___  _ ____
            #   / _ \/ _ \(_) __/__  __ __
            #  / , _/ ___/ /\ \/ _ \/ // /
            # /_/|_/_/  /_/___/ .__/\_, /
            #                /_/   /___/
            #
            #           bme280.py
            #  Read data from a digital pressure sensor.
            #
            #  Official datasheet available from :
            #  https://www.bosch-sensortec.com/bst/products/all_products/bme280
            #
            # Author : Matt Hawkins
            # Date   : 21/01/2018
            #
            # https://www.raspberrypi-spy.co.uk/
            #
            #--------------------------------------
            import smbus
            import sys
            import time
            from ctypes import c_short
            from ctypes import c_byte
            from ctypes import c_ubyte
            
            DEVICE = 0x76 # Default device I2C address
            
            try: #override device address like '0x77'
                DEVICE = int(sys.argv[1], 16)
            except:
                pass
            
            bus = smbus.SMBus(1) # Rev 2 Pi, Pi 2 & Pi 3 uses bus 1
                                 # Rev 1 Pi uses bus 0
            
            def getShort(data, index):
              # return two bytes from data as a signed 16-bit value
              return c_short((data[index+1] << 8) + data[index]).value
            
            def getUShort(data, index):
              # return two bytes from data as an unsigned 16-bit value
              return (data[index+1] << 8) + data[index]
            
            def getChar(data,index):
              # return one byte from data as a signed char
              result = data[index]
              if result > 127:
                result -= 256
              return result
            
            def getUChar(data,index):
              # return one byte from data as an unsigned char
              result =  data[index] & 0xFF
              return result
            
            def readBME280ID(addr=DEVICE):
              # Chip ID Register Address
              REG_ID     = 0xD0
              (chip_id, chip_version) = bus.read_i2c_block_data(addr, REG_ID, 2)
              return (chip_id, chip_version)
            
            def readBME280All(addr=DEVICE):
              # Register Addresses
              REG_DATA = 0xF7
              REG_CONTROL = 0xF4
              REG_CONFIG  = 0xF5
            
              REG_CONTROL_HUM = 0xF2
              REG_HUM_MSB = 0xFD
              REG_HUM_LSB = 0xFE
            
              # Oversample setting - page 27
              OVERSAMPLE_TEMP = 2
              OVERSAMPLE_PRES = 2
              MODE = 1
            
              # Oversample setting for humidity register - page 26
              OVERSAMPLE_HUM = 2
              bus.write_byte_data(addr, REG_CONTROL_HUM, OVERSAMPLE_HUM)
            
              control = OVERSAMPLE_TEMP<<5 | OVERSAMPLE_PRES<<2 | MODE
              bus.write_byte_data(addr, REG_CONTROL, control)
            
              # Read blocks of calibration data from EEPROM
              # See Page 22 data sheet
              cal1 = bus.read_i2c_block_data(addr, 0x88, 24)
              cal2 = bus.read_i2c_block_data(addr, 0xA1, 1)
              cal3 = bus.read_i2c_block_data(addr, 0xE1, 7)
            
              # Convert byte data to word values
              dig_T1 = getUShort(cal1, 0)
              dig_T2 = getShort(cal1, 2)
              dig_T3 = getShort(cal1, 4)
            
              dig_P1 = getUShort(cal1, 6)
              dig_P2 = getShort(cal1, 8)
              dig_P3 = getShort(cal1, 10)
              dig_P4 = getShort(cal1, 12)
              dig_P5 = getShort(cal1, 14)
              dig_P6 = getShort(cal1, 16)
              dig_P7 = getShort(cal1, 18)
              dig_P8 = getShort(cal1, 20)
              dig_P9 = getShort(cal1, 22)
            
              dig_H1 = getUChar(cal2, 0)
              dig_H2 = getShort(cal3, 0)
              dig_H3 = getUChar(cal3, 2)
            
              dig_H4 = getChar(cal3, 3)
              dig_H4 = (dig_H4 << 24) >> 20
              dig_H4 = dig_H4 | (getChar(cal3, 4) & 0x0F)
            
              dig_H5 = getChar(cal3, 5)
              dig_H5 = (dig_H5 << 24) >> 20
              dig_H5 = dig_H5 | (getUChar(cal3, 4) >> 4 & 0x0F)
            
              dig_H6 = getChar(cal3, 6)
            
              # Wait in ms (Datasheet Appendix B: Measurement time and current calculation)
              wait_time = 1.25 + (2.3 * OVERSAMPLE_TEMP) + ((2.3 * OVERSAMPLE_PRES) + 0.575) + ((2.3 * OVERSAMPLE_HUM)+0.575)
              time.sleep(wait_time/1000)  # Wait the required time  
            
              # Read temperature/pressure/humidity
              data = bus.read_i2c_block_data(addr, REG_DATA, 8)
              pres_raw = (data[0] << 12) | (data[1] << 4) | (data[2] >> 4)
              temp_raw = (data[3] << 12) | (data[4] << 4) | (data[5] >> 4)
              hum_raw = (data[6] << 8) | data[7]
            
              #Refine temperature
              var1 = ((((temp_raw>>3)-(dig_T1<<1)))*(dig_T2)) >> 11
              var2 = (((((temp_raw>>4) - (dig_T1)) * ((temp_raw>>4) - (dig_T1))) >> 12) * (dig_T3)) >> 14
              t_fine = var1+var2
              temperature = float(((t_fine * 5) + 128) >> 8);
            
              # Refine pressure and adjust for temperature
              var1 = t_fine / 2.0 - 64000.0
              var2 = var1 * var1 * dig_P6 / 32768.0
              var2 = var2 + var1 * dig_P5 * 2.0
              var2 = var2 / 4.0 + dig_P4 * 65536.0
              var1 = (dig_P3 * var1 * var1 / 524288.0 + dig_P2 * var1) / 524288.0
              var1 = (1.0 + var1 / 32768.0) * dig_P1
              if var1 == 0:
                pressure=0
              else:
                pressure = 1048576.0 - pres_raw
                pressure = ((pressure - var2 / 4096.0) * 6250.0) / var1
                var1 = dig_P9 * pressure * pressure / 2147483648.0
                var2 = pressure * dig_P8 / 32768.0
                pressure = pressure + (var1 + var2 + dig_P7) / 16.0
            
              # Refine humidity
              humidity = t_fine - 76800.0
              humidity = (hum_raw - (dig_H4 * 64.0 + dig_H5 / 16384.0 * humidity)) * (dig_H2 / 65536.0 * (1.0 + dig_H6 / 67108864.0 * humidity * (1.0 + dig_H3 / 67108864.0 * humidity)))
              humidity = humidity * (1.0 - dig_H1 * humidity / 524288.0)
              if humidity > 100:
                humidity = 100
              elif humidity < 0:
                humidity = 0
            
              return temperature/100.0,pressure/100.0,humidity
            
            def main():
            
              # (chip_id, chip_version) = readBME280ID()
              # print("Chip ID     :", chip_id)
              # print("Version     :", chip_version)
            
              temperature,pressure,humidity = readBME280All()
            
              print(round(temperature,1),round(humidity,1),round(pressure,1))
            
            if __name__=="__main__":
               main()
            

            @JohnGalt said in AHT20 Humidity + Temperature Sensor:

            Remote I/O error

            The given error seems to by not a program but an I/O problem.
            I’m not familiar with this sensor so I do not know how to connect and - most important - how to figure out the right “deviceAddress” - it seems that there is the error located.

            Either the address isn’t the correct one or the IO channel is somehow broken.
            For the latter came in my mind: if this is a I2C conected device - do you have enabled I2C on your Raspi?

            I’ve tried to “understand” what happens in the python script above as well as in the C-exmaple program on the Bosch product page for bme280 sensor, but didn’t got it…

            Regards,
            Ralf

            R J 3 Replies Last reply Reply Quote 0
            • R Offline
              rkorell @rkorell
              last edited by rkorell

              @JohnGalt
              just seen while re-reading my last posting:

              nodehelper.js (the part of the module which is communicating with the python program and so with the sensor) is calling python3 :

              exec(`python3 ./modules/MMM-BME280/bme280.py ${deviceAddr}`, (error, stdout) => {
              

              but the python script itself is referencing python 2 (see above post, source code of bme280.py, 1st line:

              #!/usr/bin/python
              

              I guess this must match and doesn’t …
              So may this is the cause of your problems.

              And if this is true it is may really hard to get this working because you may run in several incompatibilities and library-conflicts …

              Regards,
              Ralf

              1 Reply Last reply Reply Quote 0
              • J Offline
                JohnGalt @sdetweil
                last edited by

                @sdetweil – Thanks, Sam. It looks like I intended to send bme280.py but actually copied MMM-BME280.js. I see below where Ralf did post it, so I will look at that, too.

                1 Reply Last reply Reply Quote 1
                • J Offline
                  JohnGalt @rkorell
                  last edited by

                  @rkorell – Hi Ralf:

                  Yes, I2C is enabled and functioning. There is a test script that does return current temperature and humidity:
                  Invoking “python AHT20_test.py” does launch this script (Note - I launch from the terminal using ‘python’, not ‘python3’, telling me the system is indeed defaulting to python3):

                  # SPDX-FileCopyrightText: 2021 ladyada for Adafruit Industries
                  # SPDX-License-Identifier: MIT
                  
                  """
                  Basic `AHTx0` example test
                  """
                  
                  import time
                  import board
                  import adafruit_ahtx0
                  
                  # Create sensor object, communicating over the board's default I2C bus
                  i2c = board.I2C()  # uses board.SCL and board.SDA
                  # i2c = board.STEMMA_I2C()  # For using the built-in STEMMA QT connector on a microcontroller
                  sensor = adafruit_ahtx0.AHTx0(i2c)
                  
                  while True:
                      print("\nTemperature: %0.1f C" % sensor.temperature)
                      print("Humidity: %0.1f %%" % sensor.relative_humidity)
                      time.sleep(2)
                  
                  1 Reply Last reply Reply Quote 0
                  • J Offline
                    JohnGalt @rkorell
                    last edited by

                    @rkorell + @sdetweil - Thanks for the support. I think I have fixed this for myself by adapting an existing module (“MMM-Temperature”, // https://github.com/Tom-Hirschberger/MMM-Temperature).

                    That module calls scripts for various sensors to capture the data. I was able to adapt an existing script for use with this sensor, so I think I am good for now.

                    R 1 Reply Last reply Reply Quote 2
                    • R Offline
                      rkorell @JohnGalt
                      last edited by

                      @JohnGalt cool.
                      congratulations.
                      It’s may be worth to show the community what you have done?

                      Regards,
                      Ralf

                      J 1 Reply Last reply Reply Quote 0
                      • J Offline
                        JohnGalt @rkorell
                        last edited by

                        @rkorell Yes, I can describe how I arrived at a resolution for my particular problem - which was to replace DHTxx sensors with the more accurate AHT20 temperature and humidity sensors.

                        Caveat: I do not necessarily recommend this for the average person though, because I did not find Magic Mirror modules that natively support this sensor, and as a result had to make changes outside of the config.js and custom.css files. As usual, this puts me at risk of something breaking when the module is updated.

                        The module being used (MMM-Temperature - found at https://github.com/Tom-Hirschberger/MMM-Temperature) utilizes python scripts to capture the data from the sensor. While the module is quite complete, with script support for many sensors, I did create a new script in order to use this particular sensor.

                        The sensor is supported by Adafruit (https://learn.adafruit.com/adafruit-aht20/python-circuitpython), with instructions to install various adafruit libraries including adafruit-ahtx0 (sudo pip3 install adafruit-circuitpython-ahtx0).

                        Using those libraries, your script needs to include the following instructions:

                        import board
                        import adafruit_ahtx0
                        sensor = adafruit_ahtx0.AHTx0(board.I2C())
                        

                        One of the existing scripts supports I2C sensors using the Adafruit libraries, so it looked like a good candidate to use as a model. See htu21:

                        #!/usr/bin/env python3
                        #pip3 install adafruit-circuitpython-htu21d
                        import board
                        from adafruit_htu21d import HTU21D
                        import json
                        
                        result = {}
                        try:
                            # Create sensor object, communicating over the board's default I2C bus
                            i2c = board.I2C()  # uses board.SCL and board.SDA
                            sensor = HTU21D(i2c)
                            result["temperature_c"] = sensor.temperature
                            result["humidity"] = sensor.relative_humidity
                            result["temperature_f"] = (result["temperature_c"]*1.8) + 32
                            result["error"] = False
                        except:
                            result["temperature_c"] = 0.0
                            result["humidity"] = 0.0
                            result["temperature_f"] = (result["temperature_c"]*1.8) + 32
                            result["error"] = True
                        
                        print(json.dumps(result))
                        

                        My resulting script is aht20:

                        #!/usr/bin/env python3
                        # aht20: Modeled on htu21 
                        # pip3 install adafruit-circuitpython-htu21d
                        # pip3 install adafruit-circuitpython-ahtx0
                        import board
                        import adafruit_ahtx0
                        import json
                        
                        result = {}
                        try:
                            # Create sensor object, communicating over the board's default I2C bus
                            i2c = board.I2C()  # uses board.SCL and board.SDA
                            # sensor = HTU21D(i2c)
                            sensor = adafruit_ahtx0.AHTx0(board.I2C())
                            result["temperature_c"] = sensor.temperature
                            result["humidity"] = sensor.relative_humidity
                            result["temperature_f"] = (result["temperature_c"]*1.8) + 32
                            result["error"] = False
                        except:
                            result["temperature_c"] = 0.0
                            result["humidity"] = 0.0
                            result["temperature_f"] = (result["temperature_c"]*1.8) + 32
                            result["error"] = True
                        
                        print(json.dumps(result))
                        

                        This module is now displaying the temperature and humidity from the sensor directly connected it it. Now all I have to do is figure out the complicated css and get it to look like the other modules on my Magic Mirror.

                        Barring any objections, I will mark this as solved.

                        S R 2 Replies Last reply Reply Quote 1
                        • 1
                        • 2
                        • 1 / 2
                        • First post
                          Last post
                        Enjoying MagicMirror? Please consider a donation!
                        MagicMirror created by Michael Teeuw.
                        Forum managed by Sam, technical setup by Karsten.
                        This forum is using NodeBB as its core | Contributors
                        Contact | Privacy Policy