Open geoffklee opened 6 years ago
Nice work!
I would probably package this separately- as a general purpose way to adapt Python SMBus dependent libraries to MicroPython. While it's convenient, it has too much utility to be bundled with bme680.
Calling it something like micropython-smbus
and having it supply an smbus
importable module that you can use to shim up libraries that don't support supplying an alternate i2c object may be useful.
Thanks - that's a good idea. Of course, if I do that I'll have to stop being lazy and implement the rest of the smbus methods ;-) Hopefully it'll work for @robmarkcole in the meantime.
@gkluoe Hi Geoff, thanks for posting. I have a pycom Wipy 2.0 and have flashed the code from your repo. Do you have an example main.py where you init the i2c object as they do in the pycom docs? Have tried:
>>> sensor = bme680.BME680(i2c_addr=i2c.scan()[0])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/flash/lib/bme680.py", line 22, in __init__
ImportError: no module named 'smbus'
Happy to move this discussion to your repo but can't see an option to create an issue there. Finally it appears you intend to add this sensor to a weather-station which is my project too :)
Hi,
It's not quite a drop-in replacement for smbus (yet :) so you need to create an instance of the I2CAdapter and pass it to the BME680 constructor explicitly. OTOH, you probably don't need to set i2c_addr
when you're initing the 680, unless you've changed it from the default, so this should work (I'm on a LoPy but I think the firmware is essentially the same):
from bme680.i2c import I2CAdapter
i2c_dev = I2CAdapter(1, I2C.MASTER, baudrate=100000)
bme680.BME680(i2c_device=i2c_dev)
If you're not using the default pins, you can specify them explicitly:
i2c_dev = I2CAdapter(1, pins=('G15','G10'), baudrate=100000)
bme680.BME680(i2c_device=i2c_dev)
I've enabled issues on my fork now so if you're still having problems or have suggestions feel free to head over there! I'll tidy things up a bit and move the adapter into its own repo at some point soon.
Thanks @gkluoe that solution works on my Wipy :-)
Hi!
I tried it also on a LoPy, but the line
i2c_dev = I2CAdapter(0, I2C.MASTER, baudrate=100000, pins=('P9', 'P10'))
give me an error: NameError: name 'I2C' is not defined.
Since I'm a 'C' guy, I'm pretty new in Python coding. As far as I understand, the I2C module is loaded, bacause I get no ImportError. But why is then I2C not defined?
Cheers, Thomas
Hi - I2C isn't defined because you haven't imported it, you've imported I2CAdapter instead :-)
So, I suspect
i2c_dev = I2CAdapter(0, I2CAdapter.MASTER, baudrate=100000, pins=('P9', 'P10'))
Would work for you in this particular case.
Fwiw, I've done a bit of work to generalise this out - it's a bit of a mess to use it at the moment but the readme should get you there:
Arghh, your'e right!! Have you recognized any memory problems with your LoPy? During the burn in, I get an MemoryError: memory allocation failed, allocating 1024 bytes.
Btw am writing this up https://github.com/robmarkcole/bme680-mqtt-micropython
I get the same error – I think the burn-in script just uses up too much RAM to work on a LoPy (or is causing a lot of fragmentation somehow)
IIRC there is ~79KB free RAM on a LoPy .. it’s probably optimisable somehow…
You can use
gc.collect()
Followed by
gc.mem_free()
To see what’s going on…
The University of Edinburgh is a charitable body, registered in Scotland, with registration number SC005336.
Hi guys,
I am trying to use the i2c and bme680 libraries, but I am having some difficulties. I have quite some experience in python, but this is the first time I am working with sensors and micropython, so maybe you can help (even though this is not an actual Issue in your code on github).
I have an Adafruit HUZZAH32 - ESP32 Feather Board to which I installed micropython (following https://www.rototron.info/raspberry-pi-esp32-micropython-tutorial/ and actually I already made this work with a DHT22 sensor on another ESP32, so I know that this part should be all right, and I have also made use of the MQTT protocol there before, so that part works too), to which I have wired a BME680 using the default scl/22 and sda/23 pins.
Using only
... import bme680 from i2c import I2CAdapter ...
... i2c_dev = I2CAdapter() sensor = bme680.BME680(i2c_device=i2c_dev) ...
my code gives an error: "TypeError: 'scl' argument required" on line "i2c_dev = I2CAdapter()"
So I tried with my basic understanding getting to the bottom of this, and I can get to the next line in the code at least if I do:
i2c_dev = I2CAdapter(scl=machine.Pin(22),sda=machine.Pin(23))
which results in an error: "OSError: [Errno 19] ENODEV" on line "sensor = bme680.BME680(i2c_device=i2c_dev)"
One more thing I tried is to see if this setting sees the connected sensor, by
i2c_dev.scan() [119]
So I think that should be fine, but I have no idea how to progress from here... I had no issues make this setup work with the DHT22 sensor, but I am pretty stuck with the BME680. I would appreciate any kind of suggestions about what I am doing wrong.
Best regards, Peter
Hi. Interesting.
If scan() is working, then I'm not sure where to go with this one.
I hacked together the I2CAdapter for a LoPy and that's all I have tested it on. We have reports of it working on a WiPy too, but it's possible the generic ESP32 micropython is sufficiently different that it's doing something I didn't anticipate.
Are you able to get any more of a traceback?
You could also try the more generic version of the adapter - it might be a bit more clear what it's doing: https://github.com/gkluoe/micropython-smbus
Wait a sec! 119 == 0x77 which is the secondary address of the BME680.
By default the code looks on 0x76, hence ENODEV.
Try this:
bme680.BME680(i2c_device=i2c_dev, i2c_addr=I2C_ADDR_SECONDARY)
This helped a bit, but unluckily still getting an error - maybe this can help further:
sensor = bme680.BME680(i2c_device=i2c_dev, i2c_addr=bme680.I2C_ADDR_SECONDARY)
Traceback (most recent call last):
File "
Line 35 is return self.writeto_mem(addr, register, data) in the def write_byte_data(self, addr, register, data): function
Any ideas? (And thanks for the help in any case, it is appreciated.)
Hmm. I don't know why this would work differently on a LoPy, but this looks like a bug on my part.
I suspect that your I2C.writeto_mem()
isn't liking data
being an int
and is looking for something it can treat like a buffer. Makes perfect sense :-)
Could you try changing line 35 in i2c.py to this:
self.writeto_mem(addr, register, bytes([data]))
This is just a hunch and could be completely wrong, but if that works I'll fix it more robustly.
That was it! Wow, thanks! It is working :) I guess I can also make this change in write_i2c_block_data function and then everything should be fine. But of course if you make a robust fix, I am happy to test it on my ESP32. Again, thanks a lot for the help!
Cool! Thanks for testing that and for highlighting the bug. I've opened an issue over on micropython-smbus where I'm maintaining a more general version of the I2CAdapter.
Hi,
I followed the instructions, but still gut the below shown error:
Traceback (most recent call last):
File "<stdin>", line 18, in <module>
File "bme680.py", line 29, in __init__
File "bme680.py", line 56, in soft_reset
File "bme680.py", line 278, in _set_regs
File "i2c.py", line 35, in write_byte_data
TypeError: object with buffer protocol required
How can I solve this problem?
Thanks in advance for your help!
Christian
Hi again,
i also had a look at the smbus implementation shown at the linked issue ([https://github.com/gkluoe/micropython-smbus]), but I'm using a ESP32 and it seems like I have no clue how to change the code appropriately to get this running.
I mean especially the code line:
bus = SMBus(SMBus.MASTER, pins=('G15','G10'), baudrate=100000)
I tried using:
import usmbus
bus = usmbus.SMBus(1,scl=Pin(27), sda=Pin(26),baudrate=100000)
But the I get this error:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: extra keyword arguments given
Is this the better way? If so, can anyone help me on this?
Thanks in advance for your help!
Christian
Hi Christian2306
I encountered the same TypeError problem with a Raspberry Pi Pico in file "I2C.py", and I tried the solution from gkluoe (see obove), commented on 18 Apr 2018.
Change line 35 from I2C.py to: self.writeto_mem(addr, register, bytes([data])) this solves the issue.
Just use the default I2c :
i2c_dev = I2CAdapter(0) # defaults on Pico to SCL=Pin(9), SDA>=Pin(8), freq=400000
bme = bme680.BME680(i2c_device=i2c_dev)
while True: if bme.get_sensor_data(): output = '{0:.2f} C,{1:.2f} hPa,{2:.3f} %RH'.format( bme.data.temperature, bme.data.pressure, bme.data.humidity) print(output) sleep(1)
@arminblum Can you check if the heat_stable
parameter is getting set correctly? For me, it always returns False. print(bme.data.head_stable)
ought to do it.
@captn3m0 The "bme.data.head_stable" in my case becomes correctly true after the "burn_in_time = 120". Here my log of the bme680-all.py script with the "print(bme.data.head_stable)" line which returns true after 120s, I changed the output to json format:
{"gas_ohms": 239831.2} {"gas_ohms": 239831.2} {"gas_ohms": 239831.2} {"gas_ohms": 239654.2} {"gas_ohms": 240008.4} {"gas_ohms": 240126.6} {"gas_baseline": 250000, "humidity_baseline": 40.0} True {"temperature_C": 23.8, "pressure_hPa": 966.0, "gas_ohms_data": 240422.8, "air_quality": 91.8, "humidity": 31.5} {"temperature_C": 23.8, "pressure_hPa": 966.0, "gas_ohms_data": 240422.8, "air_quality": 91.8, "humidity": 31.5} {"temperature_C": 23.8, "pressure_hPa": 966.0, "gas_ohms_data": 240719.8, "air_quality": 91.90001, "humidity": 31.5}
Check in your script the value of your "burn_in_time" .
Not sure what the issue was, but I noticed after a while that I wasn't running the latest version (1.0.5). Updating to that fixed it.
Hello everyone,
I'm trying to use this library on an ESP32 with Micropython V1.15. Using the I2CAdapter (I define it using i2c_dev = I2CAdapter(0)
for the hardware I2C bus) I can scan for I2C devices, and get a result (in my case, just address 119 because the BME680 is the only thing attached at the moment).
However, when I try the examples from the library (indoor-air-quality.py in my case, since that's what I'm interested in), I get an error: AttributeError: 'module' object has no attribute 'OS_2X'
I have of course modified the definitions at the beginning to adapt to the use of the I2CAdapter. However it seems that the constants dont get imported correctly?
I've put constants.py and init.py into a folder bme680 on my ESP32, and use
import bme680 from i2c import * i2c_dev = I2CAdapter(0) sensor = bme680.BME680(i2c_device=i2c_dev)
I am quite sure I'm making stupid mistakes here, but I can't find them myself, so I'd be happy about any help there :D
edit: On a Raspberry Pi 4, the unmodified code works flawlessly with Python3 and having been installed from PyPi.
@elschopi I tried to use the bme680 driver in conjunction with the I2CAdaper as described in this post with MicroPython v1.14 on 2021-02-02; ESP module with ESP8266. Importing the BME680 raised an MemoryError. the garbage collector did not help (gc.collect()). ESP8266 has not enought memory to run the BME680 driver. Indeed, I used this I2CAdapter successfully with MicroPython v1.14 on 2021-02-08; Raspberry Pi Pico with RP2040. My script works fine. All imported modules (BME680.py, constants,py, i2c.py an my script bmetest68-all.py are all in on th esame level, there is no file structure on the pico.
During my numerous tests it's highly probable that I encoutered the same AttributeError:
as you mention in your post.
I used BME680.py from: (https://github.com/robmarkcole/bme680-mqtt-micropython/tree/master/lib)
my script: bmetest68-all.py: could not import the code ..
@arminblum I did get it to work after a bit. I'm now using a flat file structure (no folders) too, but have also replaced the "bme680" part in the configuration data with "constants". So now it looks like this:
sensor.set_humidity_oversample(constants.OS_2X)
(example)
instead of this:
sensor.set_humidity_oversample(bme680.OS_2X)
I did however run into memory allocation problems too, which was quite an issue as I want to collect other sensor data as well (want the BME680 as air quality sensor, and measure temperature, humidity and pressure with an BME280 as well as light levels with a TSL2561). As I'm using the ESP32 just as a client to a Raspberry Pi 4 station, I'm now sending gas resistance data over MQTT and let the RPi compute and control everything else.
I'm currently successfully and as far as I can tell stable running the pimoroni library, but some work on my end is still need to be done :P
@gkluoe Thanks for this, I am trying to implement Atlas-Scientific Sensors. See: https://github.com/Atlas-Scientific/python_AtlasOEM_lib
Traceback (most recent call last):
File "main.py", line 40, in
Any idea what I can do to fix this? Thanks!
Hi @garykuipers it looks like your sensor isn't being detected on the I2C bus. I'd suggest trying some simple code like this to scan the I2C bus to make sure that your hardware is being detected and you know which ID and pins to use.
https://gist.github.com/projetsdiy/f4330be62589ab9b3da1a4eacc6b6b1c
That will make troubleshooting the Atlas code a lot simpler:
I've made a small adapter class so that this can be used with micropython:
https://github.com/gkluoe/bme680/blob/master/library/bme680/i2c.py
@Gadgetoid would you consider a pull request to add this functionality?