Import python modules

How can I use the Import statement to load a python module into a HABapp script?

I tried the example from the python tutorial - import the fibo.py module to another script

fibo.py to import

def fib(n):    # write Fibonacci series up to n
    a, b = 0, 1
    while a < n:
        print(a, end=' ')
        a, b = b, a+b
    print()


def fib2(n):   # return Fibonacci series up to n
    result = []
    a, b = 0, 1
    while a < n:
        result.append(a)
        a, b = b, a+b
    return result

fibotest.py

import fibo

fibo.fib(1)

This looks good in pycharm, but in HABapp it fails:

2022-01-29 00:03:26.858 [ERROR] [HABApp.Rules                        ] - Error "No module named 'fibo'" in load:
2022-01-29 00:03:26.859 [ERROR] [HABApp.Rules                        ] - Could not load /etc/openhab/habapp/rules/testFibo.py!
2022-01-29 00:03:26.860 [ERROR] [HABApp.Rules                        ] - File "/opt/habapp/lib/python3.9/site-packages/HABApp/rule_manager/rule_file.py", line 80, in load
2022-01-29 00:03:26.860 [ERROR] [HABApp.Rules                        ] -     self.create_rules(created_rules)
2022-01-29 00:03:26.861 [ERROR] [HABApp.Rules                        ] - File "/opt/habapp/lib/python3.9/site-packages/HABApp/rule_manager/rule_file.py", line 66, in create_rules
2022-01-29 00:03:26.861 [ERROR] [HABApp.Rules                        ] -     runpy.run_path(str(self.path), run_name=str(self.path), init_globals={
2022-01-29 00:03:26.862 [ERROR] [HABApp.Rules                        ] - File "/usr/lib/python3.9/runpy.py", line 268, in run_path
2022-01-29 00:03:26.862 [ERROR] [HABApp.Rules                        ] -     return _run_module_code(code, init_globals, run_name,
2022-01-29 00:03:26.863 [ERROR] [HABApp.Rules                        ] - File "/usr/lib/python3.9/runpy.py", line 97, in _run_module_code
2022-01-29 00:03:26.863 [ERROR] [HABApp.Rules                        ] -     _run_code(code, mod_globals, init_globals,
2022-01-29 00:03:26.863 [ERROR] [HABApp.Rules                        ] - File "/usr/lib/python3.9/runpy.py", line 87, in _run_code
2022-01-29 00:03:26.864 [ERROR] [HABApp.Rules                        ] -     exec(code, run_globals)
2022-01-29 00:03:26.864 [ERROR] [HABApp.Rules                        ] - File "/etc/openhab/habapp/rules/testFibo.py", line 2, in testFibo.py
2022-01-29 00:03:26.865 [ERROR] [HABApp.Rules                        ] -     1    import HABApp
2022-01-29 00:03:26.865 [ERROR] [HABApp.Rules                        ] - --> 2    import fibo
2022-01-29 00:03:26.865 [ERROR] [HABApp.Rules                        ] -     3
2022-01-29 00:03:26.866 [ERROR] [HABApp.Rules                        ] -     ..................................................
2022-01-29 00:03:26.866 [ERROR] [HABApp.Rules                        ] -      HABApp = <module 'HABApp' from '/opt/habapp/lib/python3.9/site-packages/HABApp/__init__.py'>
2022-01-29 00:03:26.867 [ERROR] [HABApp.Rules                        ] -     ..................................................
2022-01-29 00:03:26.867 [ERROR] [HABApp.Rules                        ] -
2022-01-29 00:03:26.867 [ERROR] [HABApp.Rules                        ] - ModuleNotFoundError: No module named 'fibo'
2022-01-29 00:03:26.871 [WARN ] [HABApp.Rules                        ] - Failed to load /etc/openhab/habapp/rules/testFibo.py!

If you have static modules you can put them in the lib folder. However changes to the module will only be picked up after a restart.
Using rules is described in the docs.

PS: Could you add a tag habapp to your post so others can find it, please?

Thanks.

This is the correct code for my approach:

fibo.py

import HABApp


class Fibo(HABApp.Rule):

    def fib(n):    # write Fibonacci series up to n
        a, b = 0, 1
        while a < n:
            print(a, end=' ')
            a, b = b, a+b
        print()

    def fib2(n):   # return Fibonacci series up to n
        result = []
        a, b = 0, 1
        while a < n:
            result.append(a)
            a, b = b, a+b
        return result

Fibo()

TestFibo.py

import HABApp
import typing

if typing.TYPE_CHECKING:
    from .fibo import Fibo


class FiboTest(HABApp.Rule):

    def test(self):
        r = self.get_rule('ClassFibo')  # type: Fibo
        r.fib(1)


FiboTest()

Just curious: May I ask what you are doing with fibonacci series in home automation?

I just needed a simple example for module import, so I copied one from a python tutorial :wink:

A related question: I understand there is only one instance of each rule. So in this example, r1 and r2 will be references to the same instance, right?

import HABApp
import typing

if typing.TYPE_CHECKING:            # This is only here to allow
    from .rule_a import ClassA      # type hints for the IDE

class ClassB(HABApp.Rule):
    ...

    def function_b(self):

        r1 = self.get_rule('ClassA')  # type: ClassA
        r2 = self.get_rule('ClassA')  # type: ClassA

I imagined something like this example with a class for Alexa speakers that is called via two instances (with EG_XX_alexa_text as the text the speaker will say):

Class definition

import HABApp
from HABApp.openhab.items import StringItem

class AlexaSpeaker(HABApp.Rule):

    def __init__(self, alexaItem):
        super().__init__()

        self.alexaText = StringItem.get_item(alexaItem)


    def saySomething(self, textToSay):
        self.alexaText.oh_send_command(textToSay)

Two instances of the class:

alexaKitchen = AlexaSpeaker('EG_KU_alexa_text')
alexaLivingroom = AlexaSpeaker('EG_WZ_alexa_text')

alexaLivingroom.saySomething('I am alexa in the living room')
alexaKitchen.saySomething('I am alexa in the kitchen')

I understand this is not possible, is it?

In this example this is correct since you ask for the rule with the name ClassA.
Both calls will return the same rule instance thus r1 is r2

But:
You can create multiple instances of the same rule class. Each of the instances however will have a different name.

This is indeed possible and there is even an example for it in getting started.

In this example, how would I create a second instance of ClassA?

import HABApp

class ClassA(HABApp.Rule):
    ...

    def function_a(self):
      ...

ClassA()  # <-- first instance
ClassA()  # <-- second instance

It’s kind of useless however because they essentially do the same.
Take a look at that how to parametrize the rules.

I think I got it now.
Usually one would implement a class in file A, import file A to file B and instatiate it there.
Since we are working with openHab rules here, we have to instantiate the classes inheriting from HABApp.Rule in the file where they are implemented (file A) and import them to file B via self.get_rule

Right?

Correct. This is because you if you change something in file A, HABApp will automatically reload it.
But this only works if file A is isolated and does not depend on other rules.

If you import file A in file B it’s not possible to reload it any more. Because the imported module reference will still point to the old file.

But if you have static functions or classes you want to use you can always put them in the lib folder and use them normally. But to reload them you have to restart HABApp.

This topic was automatically closed 41 days after the last reply. New replies are no longer allowed.