pimoroni / bme280-python

Python library for the BME280 temperature, pressure and humidity sensor
https://shop.pimoroni.com/products/bme280-breakout
MIT License
64 stars 25 forks source link

ImportError #28

Open ShorTie8 opened 10 months ago

ShorTie8 commented 10 months ago

Trying to run some examples, but not working real well pi@Grow4:~/bme280-python/examples $ ls all-values.py dump-calibration.py relative-altitude.py temperature-forced-mode.py compensated-temperature.py local_altitude.py temperature-compare.py pi@Grow4:~/bme280-python/examples $ python compensated-temperature.py Traceback (most recent call last): File "/home/pi/bme280-python/examples/compensated-temperature.py", line 6, in <module> from bme280 import BME280 ImportError: cannot import name 'BME280' from 'bme280' (/usr/local/lib/python3.9/dist-packages/bme280/__init__.py) pi@Grow4:~/bme280-python/examples $ python dump-calibration.py Traceback (most recent call last): File "/home/pi/bme280-python/examples/dump-calibration.py", line 7, in <module> from bme280 import BME280 ImportError: cannot import name 'BME280' from 'bme280' (/usr/local/lib/python3.9/dist-packages/bme280/__init__.py) pi@Grow4:~/bme280-python/examples $ python relative-altitude.py Traceback (most recent call last): File "/home/pi/bme280-python/examples/relative-altitude.py", line 9, in <module> from bme280 import BME280 ImportError: cannot import name 'BME280' from 'bme280' (/usr/local/lib/python3.9/dist-packages/bme280/__init__.py) pi@Grow4:~/bme280-python/examples $ Jeff

Gadgetoid commented 10 months ago

How did you install the library?

Gadgetoid commented 10 months ago

Did you pip install bme280 instead of pip install pimoroni-bme280?

Edit: okay, plot twist - I just ran into exactly this error on a ROCK 5B. It was fixed with pip install --upgrade pimoroni-bme280, but that doesn't really explain why I got a corrupt package install in the first place.

ShorTie8 commented 10 months ago

sudo pip install pimoroni-bme280 is what I did

ShorTie8 commented 10 months ago

also ran the installer too...

Gadgetoid commented 10 months ago

Must be somehow getting an older version of the library, since there was a bug like this prior to v0.1.1 - https://github.com/pimoroni/bme280-python/commit/91071570e57bd0726a53f08b915090575c163e39

What do you see if you: pip freeze | grep bme280

And also:

cat /usr/local/lib/python3.9/dist-packages/bme280/__init__.py
ShorTie8 commented 10 months ago
pi@Grow4:~/bme280-python/examples $
pi@Grow4:~/bme280-python/examples $
pi@Grow4:~/bme280-python/examples $ pip freeze | grep bme280
bme280==0.6
pimoroni-bme280==0.1.1
RPi.bme280==0.2.4

pi@Grow4:~/bme280-python/examples $ cat /usr/local/lib/python3.9/dist-packages/bme280/__init__.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# The MIT License (MIT)
#
# Copyright (c) 2016 Richard Hull
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", 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
# AUTHORS OR COPYRIGHT HOLDERS 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.

"""
Raspberry Pi BME280 Driver.
"""

__version__ = "0.2.4"

import datetime
import time
import uuid

from bme280.reader import reader
import bme280.const as oversampling
import pytz

# Oversampling modes
oversampling.x1 = 1
oversampling.x2 = 2
oversampling.x4 = 3
oversampling.x8 = 4
oversampling.x16 = 5

DEFAULT_PORT = 0x76

class uncompensated_readings(object):

    def __init__(self, block):
        self._block = block
        self.pressure = (block[0] << 16 | block[1] << 8 | block[2]) >> 4
        self.temperature = (block[3] << 16 | block[4] << 8 | block[5]) >> 4
        self.humidity = block[6] << 8 | block[7]

    def __repr__(self):
        return "uncompensated_reading(temp=0x{0:08X}, pressure=0x{1:08X}, humidity=0x{2:08X}, block={3})".format(
            self.temperature, self.pressure, self.humidity,
            ":".join("{0:02X}".format(c) for c in self._block))

class compensated_readings(object):
    """
    Compensation formulas translated from Appendix A (8.1) of BME280 datasheet:

       * Temperature in °C, double precision. Output value of "51.23"
         equals 51.23 °C

       * Pressure in hPa as double. Output value of "963.862" equals
         963.862 hPa

       * Humidity in %rH as as double. Output value of "46.332" represents
         46.332 %rH
    """
    def __init__(self, raw_readings, compensation_params):
        self._comp = compensation_params
        self.id = uuid.uuid4()
        self.uncompensated = raw_readings
        self.timestamp = datetime.datetime.utcnow().replace(tzinfo=pytz.UTC)
        self.temperature = self.__tfine(raw_readings.temperature) / 5120.0
        self.humidity = self.__calc_humidity(raw_readings.humidity,
                                             raw_readings.temperature)
        self.pressure = self.__calc_pressure(raw_readings.pressure,
                                             raw_readings.temperature) / 100.0

    def __tfine(self, t):
        v1 = (t / 16384.0 - self._comp.dig_T1 / 1024.0) * self._comp.dig_T2
        v2 = ((t / 131072.0 - self._comp.dig_T1 / 8192.0) ** 2) * self._comp.dig_T3
        return v1 + v2

    def __calc_humidity(self, h, t):
        res = self.__tfine(t) - 76800.0
        res = (h - (self._comp.dig_H4 * 64.0 + self._comp.dig_H5 / 16384.0 * res)) * (self._comp.dig_H2 / 65536.0 * (1.0 + self._comp.dig_H6 / 67108864.0                                                                                    * res * (1.0 + self._comp.dig_H3 / 67108864.0 * res)))
        res = res * (1.0 - (self._comp.dig_H1 * res / 524288.0))
        return max(0.0, min(res, 100.0))

    def __calc_pressure(self, p, t):
        v1 = self.__tfine(t) / 2.0 - 64000.0
        v2 = v1 * v1 * self._comp.dig_P6 / 32768.0
        v2 = v2 + v1 * self._comp.dig_P5 * 2.0
        v2 = v2 / 4.0 + self._comp.dig_P4 * 65536.0
        v1 = (self._comp.dig_P3 * v1 * v1 / 524288.0 + self._comp.dig_P2 * v1) / 524288.0
        v1 = (1.0 + v1 / 32768.0) * self._comp.dig_P1

        # Prevent divide by zero
        if v1 == 0:
            return 0

        res = 1048576.0 - p
        res = ((res - v2 / 4096.0) * 6250.0) / v1
        v1 = self._comp.dig_P9 * res * res / 2147483648.0
        v2 = res * self._comp.dig_P8 / 32768.0
        res = res + (v1 + v2 + self._comp.dig_P7) / 16.0
        return res

    def __repr__(self):
        return "compensated_reading(id={0}, timestamp={1:%Y-%m-%d %H:%M:%S.%f%Z}, temp={2:0.3f} °C, pressure={3:0.2f} hPa, humidity={4:0.2f} % rH)".format                                                                                   (
            self.id, self.timestamp, self.temperature, self.pressure, self.humidity)

class params(dict):
    __getattr__ = dict.__getitem__
    __setattr__ = dict.__setitem__
    __delattr__ = dict.__delitem__

class memoize:
    def __init__(self, f):
        self.f = f
        self.memo = {}

    def __call__(self, *args):
        if args not in self.memo:
            self.memo[args] = self.f(*args)
        return self.memo[args]

def load_calibration_params(bus, address=DEFAULT_PORT):
    """
    The BME280 output consists of the ADC output values. However, each sensing
    element behaves differently. Therefore, the actual pressure and temperature
    must be calculated using a set of calibration parameters.

    The calibration parameters are subsequently used to with some compensation
    formula to perform temperature readout in degC, humidity in % and pressure
    in hPA.
    """
    read = reader(bus, address)
    compensation_params = params()

    # Temperature trimming params
    compensation_params.dig_T1 = read.unsigned_short(0x88)
    compensation_params.dig_T2 = read.signed_short(0x8A)
    compensation_params.dig_T3 = read.signed_short(0x8C)

    # Pressure trimming params
    compensation_params.dig_P1 = read.unsigned_short(0x8E)
    compensation_params.dig_P2 = read.signed_short(0x90)
    compensation_params.dig_P3 = read.signed_short(0x92)
    compensation_params.dig_P4 = read.signed_short(0x94)
    compensation_params.dig_P5 = read.signed_short(0x96)
    compensation_params.dig_P6 = read.signed_short(0x98)
    compensation_params.dig_P7 = read.signed_short(0x9A)
    compensation_params.dig_P8 = read.signed_short(0x9C)
    compensation_params.dig_P9 = read.signed_short(0x9E)

    # Humidity trimming params
    compensation_params.dig_H1 = read.unsigned_byte(0xA1)
    compensation_params.dig_H2 = read.signed_short(0xE1)
    compensation_params.dig_H3 = read.signed_byte(0xE3)

    e4 = read.signed_byte(0xE4)
    e5 = read.signed_byte(0xE5)
    e6 = read.signed_byte(0xE6)

    compensation_params.dig_H4 = e4 << 4 | e5 & 0x0F
    compensation_params.dig_H5 = ((e5 >> 4) & 0x0F) | (e6 << 4)
    compensation_params.dig_H6 = read.signed_byte(0xE7)

    return compensation_params

__cache_calibration_params = memoize(load_calibration_params)

def __calc_delay(t_oversampling, h_oversampling, p_oversampling):
    t_delay = 0.000575 + 0.0023 * (1 << t_oversampling)
    h_delay = 0.000575 + 0.0023 * (1 << h_oversampling)
    p_delay = 0.001250 + 0.0023 * (1 << p_oversampling)
    return t_delay + h_delay + p_delay

def sample(bus, address=DEFAULT_PORT, compensation_params=None, sampling=oversampling.x1):
    """
    Primes the sensor for reading (defaut: x1 oversampling), pauses for a set
    amount of time so that the reading stabilizes, and then returns a
    compensated reading object with the following attributes:
        * timestamp (Python's datetime object) when reading was taken.
        * temperature, in degrees Celcius.
        * humidity, in % relative humidity.
        * pressure, in hPa.
    """
    if compensation_params is None:
        compensation_params = __cache_calibration_params(bus, address)

    mode = 1  # forced
    t_oversampling = sampling or oversampling.x1
    h_oversampling = sampling or oversampling.x1
    p_oversampling = sampling or oversampling.x1

    bus.write_byte_data(address, 0xF2, h_oversampling)  # ctrl_hum
    bus.write_byte_data(address, 0xF4, t_oversampling << 5 | p_oversampling << 2 | mode)  # ctrl
    delay = __calc_delay(t_oversampling, h_oversampling, p_oversampling)
    time.sleep(delay)

    block = bus.read_i2c_block_data(address, 0xF7, 8)
    raw_data = uncompensated_readings(block)
    return compensated_readings(raw_data, compensation_params)
Gadgetoid commented 10 months ago

Okay that bme280 library is not our bme280 library, I wonder if it's just shadowing ours or was installed by the installer accidentally.

Try:

pip uninstall bme280
pip install --upgrade pimoroni-bme280
ShorTie8 commented 10 months ago

pi@Grow4:~ $ pip uninstall bme280 pip install --upgrade pimoroni-bme280 Found existing installation: bme280 0.6 Uninstalling bme280-0.6: Would remove: /usr/local/bin/read_bme280 /usr/local/lib/python3.9/dist-packages/bme280-0.6.dist-info/ /usr/local/lib/python3.9/dist-packages/bme280/ Would not remove (might be manually added): /usr/local/lib/python3.9/dist-packages/bme280/const.py /usr/local/lib/python3.9/dist-packages/bme280/reader.py Proceed (y/n)? y ERROR: Exception: Traceback (most recent call last): File "/usr/lib/python3.9/shutil.py", line 806, in move os.rename(src, real_dst) PermissionError: [Errno 13] Permission denied: '/usr/local/bin/' -> '/tmp/pip-uninstall-9ouiakkc'

During handling of the above exception, another exception occurred:

Traceback (most recent call last): File "/usr/lib/python3/dist-packages/pip/_internal/cli/base_command.py", line 223, in _main status = self.run(options, args) File "/usr/lib/python3/dist-packages/pip/_internal/commands/uninstall.py", line 89, in run uninstall_pathset = req.uninstall( File "/usr/lib/python3/dist-packages/pip/_internal/req/req_install.py", line 694, in uninstall uninstalled_pathset.remove(auto_confirm, verbose) File "/usr/lib/python3/dist-packages/pip/_internal/req/req_uninstall.py", line 403, in remove moved.stash(path) File "/usr/lib/python3/dist-packages/pip/_internal/req/req_uninstall.py", line 292, in stash renames(path, new_path) File "/usr/lib/python3/dist-packages/pip/_internal/utils/misc.py", line 355, in renames shutil.move(old, new) File "/usr/lib/python3.9/shutil.py", line 818, in move rmtree(src) File "/usr/lib/python3.9/shutil.py", line 718, in rmtree _rmtree_safe_fd(fd, path, onerror) File "/usr/lib/python3.9/shutil.py", line 675, in _rmtree_safe_fd onerror(os.unlink, fullname, sys.exc_info()) File "/usr/lib/python3.9/shutil.py", line 673, in _rmtree_safe_fd os.unlink(entry.name, dir_fd=topfd) PermissionError: [Errno 13] Permission denied: 'read_bme280' Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple Requirement already satisfied: pimoroni-bme280 in /usr/local/lib/python3.9/dist-packages (0.1.1) Collecting pimoroni-bme280 Downloading pimoroni_bme280-1.0.0-py3-none-any.whl (7.8 kB) Collecting i2cdevice>=1.0.0 Downloading https://www.piwheels.org/simple/i2cdevice/i2cdevice-1.0.0-py3-none-any.whl (10 kB) Requirement already satisfied: smbus2 in /usr/local/lib/python3.9/dist-packages (from i2cdevice>=1.0.0->pimoroni-bme280) (0.4.3) Installing collected packages: i2cdevice, pimoroni-bme280 Successfully installed i2cdevice-1.0.0 pimoroni-bme280-1.0.0 pi@Grow4:~ $

ShorTie8 commented 10 months ago

i've probably have install a few bme280 libraries playing

ShorTie8 commented 10 months ago

Ok, I know there are Turtles and then Me. Na, Been waiting on my pi5. So it's fresh everything. Like only history entries.

So, got me, still don't work

` pi@pi5:~ $ history 1 sudo apt update 2 sudo apt upgrade 3 sudo apt install python3-full 4 sudo apt install i2c-tools 5 sudo apt autoremove pi@pi5:~ $ i2cdetect -a 1 70: -- -- -- -- -- -- 76 -- -- -- -- -- -- -- -- --

locate bme280.py /usr/local/lib/python3.9/dist-packages/bme280/bme280.py root@Grow4:/home/pi# ls -l /usr/local/lib/python3.9/dist-packages/bme28* /usr/local/lib/python3.9/dist-packages/bme280: total 40 -rw-r--r-- 1 root root 1037 Oct 16 01:40 bme280_i2c.py -rw-r--r-- 1 root root 8393 Oct 16 01:40 bme280.py -rw-r--r-- 1 root root 1699 Nov 5 00:50 const.py -rw-r--r-- 1 root root 8357 Nov 5 00:50 init.py drwxr-xr-x 2 root root 4096 Nov 5 00:50 pycache -rw-r--r-- 1 root root 1971 Nov 5 00:50 reader.py

/usr/local/lib/python3.9/dist-packages/bme280-0.6.dist-info: total 32 -rw-r--r-- 1 root root 337 Oct 16 01:40 DESCRIPTION.rst -rw-r--r-- 1 root root 52 Oct 16 01:40 entry_points.txt -rw-r--r-- 1 root root 4 Oct 16 01:40 INSTALLER -rw-r--r-- 1 root root 1105 Oct 16 01:40 METADATA -rw-r--r-- 1 root root 1079 Oct 16 01:40 metadata.json -rw-r--r-- 1 root root 1184 Oct 16 01:40 RECORD -rw-r--r-- 1 root root 0 Oct 16 01:40 REQUESTED -rw-r--r-- 1 root root 7 Oct 16 01:40 top_level.txt -rw-r--r-- 1 root root 110 Oct 16 01:40 WHEEL

pi@pi5:~ $ python3 -m pip install pimoroni-bme280 error: externally-managed-environment

× This environment is externally managed ?-> To install Python packages system-wide, try apt install python3-xyz, where xyz is the package you are trying to install.

If you wish to install a non-Debian-packaged Python package,
create a virtual environment using python3 -m venv path/to/venv.
Then use path/to/venv/bin/python and path/to/venv/bin/pip. Make
sure you have python3-full installed.

For more information visit http://rptl.io/venv

note: If you believe this is a mistake, please contact your Python installation or OS distribution provider. You can override this, at the risk of breaking your Python installation or OS, by passing --break-system-packages.

`

Gadgetoid commented 10 months ago

You should now be working in a virtual environment. I've explained why in exhaustive detail here: https://github.com/pimoroni/boilerplate-python/pull/13

If it sounds like tedious nonsense to you, welcome to the last two months of my life.

In short, you'll need to:

sudo apt install python3-virtualenvwrapper virtualenvwrapper
source /usr/share/virtualenvwrapper/virtualenvwrapper.sh
mkvirtualenv your_project_name

Then install everything into that virtual environment with pip install and to get back into the environment:

source /usr/share/virtualenvwrapper/virtualenvwrapper.sh
workon your_project_name

You can add source /usr/share/virtualenvwrapper/virtualenvwrapper.sh to the bottom of ~/.bashrc to avoid having to repeat that step every time.