pimoroni / sgp30-python

Python library for the SGP30 air quality sensor
https://shop.pimoroni.com/products/sgp30-air-quality-sensor-breakout
MIT License
38 stars 18 forks source link

Too many open files: '/dev/i2c-1' #5

Closed Rayn0r closed 4 years ago

Rayn0r commented 4 years ago

I'm trying to use the SGP30 sensor in a collectd plugin. The plugin is suppossed to write the eco2 value to an InfluxDB. Therefore I'm initiliazing the sensor with:

#!/usr/bin/env python3
from sgp30 import SGP30
import sys

sgp30 = SGP30()
sgp30.start_measurement()

before starting collectd.

From within collectd the follwowing code is executed every 10 seconds.

    sgp30 = SGP30()
    eco2s, tvocs = sgp30.command('measure_air_quality')

and then written to the InfluxDB. Sending the command seems to call SMBUS.open() implicitly in line 76: self._i2c_dev.i2c_rdwr(msg_w) But there is no self._i2c_dev.close().

In my case this left 11 file handles to /dev/i2c-1 open on every call of the plugin script. So the file handle needs to be closed somewhere...

Where is the best place in the lib to cleanup the connection? As a quick and dirty solution I added a close()-call at line 90 after verified = []

Gadgetoid commented 4 years ago

If a bus number is passed to SMBus then it will open the i2c device there and then, eg: SMbus(1), see: https://github.com/kplindegaard/smbus2/blob/3074717ff02fa5214fc5f1f0d2e5a2827583d6ba/smbus2/smbus2.py#L278-L279

However you are correct, the lib does not do any explicit cleanup of the connection since most use cases implicitly close it when Python itself is closed.

Python has a __del__ magic method, or "class destructor" for when classes go out of scope and are cleaned up. I don't know if it would suffice to close the device here, but it might be worth a try:

def __del__(self):
    self._i2c_dev.close()

This is probably something I should roll out across all of our libraries, since they are not currently well suited to being used in this manner- ie as part of a plugin that creates/destroys the class repeatedly- but they probably should be.

Rayn0r commented 4 years ago

@Gadgetoid

With your suggested patch applied:

diff --git a/library/sgp30/__init__.py b/library/sgp30/__init__.py
index e458bd4..32619d9 100644
--- a/library/sgp30/__init__.py
+++ b/library/sgp30/__init__.py
@@ -173,3 +173,7 @@ class SGP30:

     def set_baseline(self, eco2, tvoc):
         self.command('set_baseline', eco2, tvoc)
+
+    def __del__(self):
+        self._i2c_dev.close()
+

the open file count to /dev/i2c-1 remains at 11 all the time. So I'd say this cures the problem quite nicely.

Thank you very much.

Gadgetoid commented 4 years ago

Fix in v0.0.2

mansooralmansoob commented 2 years ago

in this sensor i have problem the sensor address before i run a code gives me address 0x58 by using i2cdetect -y 1 and not gives me any reading except eco2 400ppm and tvo 0ppb and when i chick address doesn't give 0x58 however this sensor run in correct manner for many times before