chrisb2 / pi_ina219

This Python library supports the INA219 voltage, current and power monitor from Texas Instruments with a Raspberry Pi using the I2C bus. The intent of the library is to make it easy to use the quite complex functionality of this sensor.
MIT License
114 stars 34 forks source link

ImportError: cannot import name INA219 #23

Closed Jamos1988 closed 4 years ago

Jamos1988 commented 4 years ago

Hi, I am using this code with your library and get the error: ImportError: cannot import name INA219

#!/usr/bin/env python

import socket, time, math, csv, datetime, subprocess, sys, os

op_folder = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..')
sys.path.append(op_folder+'/classes')
#from ads1115 import Ads1115
#from conf_analog import Conf_analog
from ina219 import INA219
from ina219 import DeviceRangeError

SHUNT_OHMS = 0.01

conf_analog=Conf_analog()
home = conf_analog.home

if len(sys.argv)>1:
    if sys.argv[1]=='settings':
        print home+'/.openplotter/openplotter_analog.conf'
        subprocess.Popen(['leafpad',home+'/.openplotter/openplotter_analog.conf'])
    exit
else:

    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

    poll_interval = 1
    rate_analog = 1

    tick_analog=time.time()
    ina = INA219(SHUNT_OHMS,1.0,0x41)
    ina.configure()

    try:
        inaV = ina.voltage()
        inaA = ina.current()/1000
        inaW = inaV*inaA
    except DeviceRangeError as e:
        print e

    while True:
        tick2=time.time()
        time.sleep(poll_interval*1.0/1000.0)
        #GENERATE   

        if tick2-tick_analog > rate_analog:
            tick_analog=time.time()

            list_signalk_path1=[]
            list_signalk1=[]

            try:
                inaV = inaV*0.8 +ina.voltage()*0.2
                inaA = inaA*0.8 +ina.current()/1000*0.2
                inaW = inaV*inaA
            except DeviceRangeError as e:
                print e

            SignalK = '{"updates": [{"$source": "OPsensors.I2C.ina219","values":[ '
            Erg=''
            Erg += '{"path": "electrical.batteries.rpi.current","value":'+str(inaA)+'},'
            Erg += '{"path": "electrical.batteries.rpi.voltage","value":'+str(inaV)+'},'
            Erg += '{"path": "electrical.batteries.rpi.power","value":'+str(inaW)+'},'          
            SignalK +=Erg[0:-1]+']}]}\n'
            sock.sendto(SignalK, ('127.0.0.1', 55557))

The following code is working perfectly, so I know it is not a hardware problem:

#!/usr/bin/env python

import logging
from ina219 import INA219

SHUNT_OHMS = 0.01
MAX_EXPECTED_AMPS = 6

def read():
    ina = INA219(SHUNT_OHMS, MAX_EXPECTED_AMPS, log_level=logging.INFO)
    ina.configure(ina.RANGE_16V, ina.GAIN_AUTO)

    print("Bus Voltage    : %.3f V" % ina.voltage())
    print("Bus Current    : %.3f mA" % ina.current())
    print("Supply Voltage : %.3f V" % ina.supply_voltage())
    print("Shunt voltage  : %.3f mV" % ina.shunt_voltage())
    print("Power          : %.3f mW" % ina.power())

if __name__ == "__main__":
    read()

Hope you can help! Been trying for days, with no luck to get the first script running. I am running it with python ina219.py and not python3 ina219.py

Regards,

Jamos

chrisb2 commented 4 years ago

As this is failing quite early as it tries to import the ina219 library, I would be suspicious of the following lines: op_folder = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..') sys.path.append(op_folder+'/classes') If you put these in the working script does it fail?

regards, Chris

Jamos1988 commented 4 years ago

Thank you for your quick reply! By adding the lines, the previously working script is still working:

#!/usr/bin/env python

import logging, socket, time, math, csv, datetime, subprocess, sys, os
op_folder = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..')
sys.path.append(op_folder+'/classes')
from ina219 import INA219

SHUNT_OHMS = 0.01
MAX_EXPECTED_AMPS = 6

def read():
    ina = INA219(SHUNT_OHMS, MAX_EXPECTED_AMPS, log_level=logging.INFO)
    ina.configure(ina.RANGE_16V, ina.GAIN_AUTO)

    print("Bus Voltage    : %.3f V" % ina.voltage())
    print("Bus Current    : %.3f mA" % ina.current())
    print("Supply Voltage : %.3f V" % ina.supply_voltage())
    print("Shunt voltage  : %.3f mV" % ina.shunt_voltage())
    print("Power          : %.3f mW" % ina.power())

if __name__ == "__main__":
    read()

However, I had to add the lineimport logging, socket, time, math, csv, datetime, subprocess, sys, os first.

Result:

2020-02-07 11:52:15,226 - INFO - INA219 gain set to 0.08V
2020-02-07 11:52:15,229 - INFO - INA219 calibrate called with: bus max volts: 16V, max shunt volts: 0.08V, max expected amps: 6.000A
2020-02-07 11:52:15,229 - INFO - INA219 max possible current: 8.000A
2020-02-07 11:52:15,230 - INFO - INA219 max expected current: 6.000A
2020-02-07 11:52:15,230 - INFO - INA219 current LSB: 6.250e-05 A/bit
2020-02-07 11:52:15,231 - INFO - INA219 power LSB: 1.250e-03 W/bit
2020-02-07 11:52:15,231 - INFO - INA219 max current before overflow: 2.0480A
2020-02-07 11:52:15,232 - INFO - INA219 max shunt voltage before overflow: 20.4800mV
2020-02-07 11:52:15,232 - INFO - INA219 calibration: 0xfffe (65534)
Bus Voltage    : 12.716 V
Bus Current    : 102.003 mA
Supply Voltage : 12.769 V
Shunt voltage  : 0.900 mV
Power          : 1155.035 mW

Also, by placing the line in the non-working script to the top, like in this example, it still fails:

#!/usr/bin/env python

from ina219 import INA219
from ina219 import DeviceRangeError

import logging, socket, time, math, csv, datetime, subprocess, sys, os

op_folder = os.path.join(os.path.dirname(os.path.realpath(__file__)), '..')
sys.path.append(op_folder+'/classes')

SHUNT_OHMS = 0.01
MAX_EXPECTED_AMPS = 6

conf_analog=Conf_analog()
home = conf_analog.home

if len(sys.argv)>1:
    if sys.argv[1]=='settings':
        print home+'/.openplotter/openplotter_analog.conf'
        subprocess.Popen(['leafpad',home+'/.openplotter/openplotter_analog.conf'])
    exit
else:

    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

    poll_interval = 1
    rate_analog = 1

    tick_analog=time.time()
    ina = INA219(SHUNT_OHMS,0.01,0x40)
    ina.configure()

    try:
        inaV = ina.voltage()
        inaA = ina.current()/1000
        inaW = inaV*inaA
    except DeviceRangeError as e:
        print e

    while True:
        tick2=time.time()
        time.sleep(poll_interval*1.0/1000.0)
        #GENERATE   

        if tick2-tick_analog > rate_analog:
            tick_analog=time.time()

            list_signalk_path1=[]
            list_signalk1=[]

            try:
                inaV = inaV*0.8 +ina.voltage()*0.2
                inaA = inaA*0.8 +ina.current()/1000*0.2
                inaW = inaV*inaA
            except DeviceRangeError as e:
                print e

            SignalK = '{"updates": [{"$source": "OPsensors.I2C.ina219","values":[ '
            Erg=''
            Erg += '{"path": "electrical.batteries.rpi.current","value":'+str(inaA)+'},'
            Erg += '{"path": "electrical.batteries.rpi.voltage","value":'+str(inaV)+'},'
            Erg += '{"path": "electrical.batteries.rpi.power","value":'+str(inaW)+'},'          
            SignalK +=Erg[0:-1]+']}]}\n'
            sock.sendto(SignalK, ('127.0.0.1', 55557))
chrisb2 commented 4 years ago

Quite puzzling. I had a play with your last code example (the none working code with import as first line). I cut out the first 6 lines and pasted them into a test file (test2.py) on my Pi, because I use Python 3 I had to make the first line: #!/usr/bin/env python3 the code gave no error when executed with: python3 test2.py or: ./test2.py however if I tried to execute with Python 2 (which does not have ina219 library installed) using: python test2.py I got the same import error as you. I wonder if there is some confusion with Python versions on your system. What do the following commands return: python -V python3 -V pip list | grep ina219 pip3 list | grep ina219

Chris

Jamos1988 commented 4 years ago

Thanks for your research and testing, I tried the following:

pi@openplotter:~ $ python -V
Python 2.7.13
pi@openplotter:~ $ python3 -V
Python 3.5.3
pi@openplotter:~ $ pip list | grep ina219
DEPRECATION: The default format will switch to columns in the future. You can use --format=(legacy|columns) (or define a format=(legacy|columns) in your pip.conf under the [list] section) to disable this warning.
pi-ina219 (1.3.0)
pi@openplotter:~ $ pip3 list | grep ina219
DEPRECATION: The default format will switch to columns in the future. You can use --format=(legacy|columns) (or define a format=(legacy|columns) in your pip.conf under the [list] section) to disable this warning.
pi-ina219 (1.3.0)
pi@openplotter:~ $ 

When I change the first line to #!/usr/bin/env python3 I get the following error when executing:

pi@openplotter:~/.openplotter/tools/ina219 $ python ina219test.py
Traceback (most recent call last):
  File "ina219test.py", line 10, in <module>
    from ina219 import INA219
  File "/home/pi/.openplotter/tools/ina219/ina219.py", line 22, in <module>
    from ads1115 import Ads1115
ImportError: No module named ads1115

Even when removing or commenting the following lines I still get the error:

#from ads1115 import Ads1115
#from conf_analog import Conf_analog

Old error still persist:

pi@openplotter:~/.openplotter/tools/ina219 $ python ina219test.py
Traceback (most recent call last):
  File "ina219test.py", line 10, in <module>
    from ina219 import INA219
  File "/home/pi/.openplotter/tools/ina219/ina219.py", line 10, in <module>
    from ina219 import INA219
ImportError: cannot import name INA219
chrisb2 commented 4 years ago

One last idea, try un-installing the ina219 library and re-installing, you can un-install with pip.

Otherwise I suggest raising an question in the Python 3 support forum or on Stack Overflow, as I suspect there is something wrong with your Python installation, debugging this sort of issue is not something I know much about.

Chris

Jamos1988 commented 4 years ago

Thanks Chris, I did this without any luck. However, I did make some progress by trying a code that is specific for python3, and it seems I am now a little step further:

Code:

#!/usr/bin/env python3

# This file is part of Openplotter.
# Copyright (C) 2020 by sailoog <https://github.com/sailoog/openplotter>
#                     e-sailing <https://github.com/e-sailing/openplotter>
# Openplotter is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 2 of the License, or
# any later version.
# Openplotter is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Openplotter. If not, see <http://www.gnu.org/licenses/>.

# This tool should receive data from ina219 
# convert the data and send it to the signal k server
# You need to install pi-ina219 (sudo pip3 install pi-ina219)

import socket, time, math, csv, datetime, subprocess, sys, os

op_folder = os.path.join(os.path.dirname(os.path.realpath(__file__)), '../..')
sys.path.append(op_folder+'/classes')
from ina219 import INA219
from ina219 import DeviceRangeError

SHUNT_OHMS = 0.01

if len(sys.argv)>1:
    if sys.argv[1]=='settings':
        pass
else:

    sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

    poll_interval = 1000

    ina = INA219(SHUNT_OHMS,1.0,1,0x40)
    ina.configure()

    try:
        inaV = ina.voltage()
        inaA = ina.current()/1000
        inaW = inaV*inaA
    except DeviceRangeError as e:
        print(e)

    while True:
        time.sleep(poll_interval*1.0/1000.0)

        try:
            inaV = inaV*0.8 +ina.voltage()*0.2
            inaA = inaA*0.8 +ina.current()/1000*0.2
            inaW = inaV*inaA
        except DeviceRangeError as e:
            print(e)

        SignalK = '{"updates": [{"$source": "OPsensors.I2C.ina219","values":[ '
        Erg=''
        Erg += '{"path": "electrical.batteries.rpi.current","value":'+str(inaA)+'},'
        Erg += '{"path": "electrical.batteries.rpi.voltage","value":'+str(inaV)+'},'
        Erg += '{"path": "electrical.batteries.rpi.power","value":'+str(inaW)+'},'            
        SignalK +=Erg[0:-1]+']}]}\n'
        sock.sendto(SignalK.encode(), ('127.0.0.1', 20220))

Doesn't give me the old error (yet) but does give me another one, namely:

Traceback (most recent call last):
  File "ina219test.py", line 26, in <module>
    from ina219 import INA219
  File "/home/pi/.openplotter/tools/ina219/ina219.py", line 34
    print home+'/.openplotter/openplotter_analog.conf'
             ^
SyntaxError: Missing parentheses in call to 'print'

I feel that I am moving along now, I've read this on stackoverflow:

https://stackoverflow.com/questions/25445439/what-does-syntaxerror-missing-parentheses-in-call-to-print-mean-in-python

But I don't know if and how I should change the following line, if that would be the solotuion:

op_folder = os.path.join(os.path.dirname(os.path.realpath(__file__)), '../..')
sys.path.append(op_folder+'/classes')

Hope you can assist me once more.

Regards,

Jamos

chrisb2 commented 4 years ago

The ina219 library has no print statements and anyway is fully Python 3 compatible, but fishing about in the open plotter source, I can see Python 2 print statements, for example in ads1115.py, so it seems it may be one of these that is causing the problem.

If you look at this change in a PR from August 2019, it shows exactly the line in your error. Perhaps all you need to do is update to the latest version of open plotter?

You may encounter more none Python3 code in open plotter, in that case I suggest forking the repo and fixing them as you find them. You could then raise a PR to contribute them back to the main repo.

Chris

chrisb2 commented 4 years ago

Closing, please re-open if required.