HABApp - Easy automation with openHAB

Hi it’s me again. Question about converting some rules, that have a defined timer that I can cancel at later events.

Consider this:

rule "Door last close"
when
        Item Dsc_Zone1_General_Status changed from OPEN to CLOSED or
        Item Dsc_Zone2_General_Status changed from OPEN to CLOSED or
        Item Dsc_Zone3_General_Status changed from OPEN to CLOSED
then
        
        if(tAlarmCheck!==null) {
                tAlarmCheck.cancel
                tAlarmCheck = null
        }

        tAlarmCheck = createTimer(now.plusMinutes(5)) [|
                postSlack.apply("Remember to set alarm!")
        ]
end

Everything time this rule runs, it will first check for existing instances of timer, cancel it then reset it.

In habapp, I can do self.run_at, but if the event got triggered in in less than 5 minutes, how do I cancel the previous scheduled event?

Thanks,
Joe

self.run_at will return a object which should have a cancel() function.
If you use an IDE (e.g. pycharm) it will pop up as soon as you hit the .

I understand there is a cancel function. However, I don’t understand how to “find” the scheduled callback and then cancel it.

Do I have to loop thru self.__future_events? Since it’s a private member, I don’t have any mean to access that.

For example,

class SomeRules(HABApp.Rule):
    def __init__(self):
        super().__init__()
        self.listen_event("Dsc_Zone1_General_Status", self.__send_reminder, ItemStateChangedEvent)
        self.listen_event("Dsc_Zone2_General_Status", self.__send_reminder, ItemStateChangedEvent)
        self.listen_event("Dsc_Zone3_General_Status", self.__send_reminder, ItemStateChangedEvent)

    def __send_reminder(self, event)
        #if event already exists <-------------This part I don't know how to do????
            ScheduledCallback.cancel()

        self.run_at(
            time=datetime.timedelta(seconds=600),
            callback=somefunction
        )

The part I can’t figure out is let say if Dsc_Zone1_General_Status triggers and scheduled a callback at 10 minutes later. Then Dsc_Zone2_General_Status triggers 5 minutes later. How do cancel the scheduled callback set by Dsc_Zone1_General_Status before scheduling another callback?

The rule is supposed to keep cancelling callbacks (or timers in Openhab Rules) and set new ones if any of those item triggers during the 10 minute scheduled time.

Thanks,
Joe

You are thinking way to complicated, the sheduled cb will be returned from the run_XX function.

class SomeRules(HABApp.Rule):
    def __init__(self):
        super().__init__()
        self.listen_event("Dsc_Zone1_General_Status", self.__send_reminder, ItemStateChangedEvent)
        self.listen_event("Dsc_Zone2_General_Status", self.__send_reminder, ItemStateChangedEvent)
        self.listen_event("Dsc_Zone3_General_Status", self.__send_reminder, ItemStateChangedEvent)

        self.timer = None

    def __send_reminder(self, event):
        if self.timer is not None:
            self.timer.cancel()
            self.timer = None

        self.timer = self.run_at(
            time=datetime.timedelta(seconds=600),
            callback=somefunction
        )

Edit:
You could also listen to ValueChangedEvent insted of the specific openhab event (ItemStateChangedEvent).

Damn, it’s so easy when you see the answer :slight_smile:. I am still grasping how habapp works. Thank you for being patient.

FYI, I am moving all my rules over, if you haven’t already noticed.

Thanks,
Joe

1 Like

@goodfore:
Check out MultiValue , I just did some renaming and small rework. It really makes overlapping states and different modes easy to implement.


Version 0.7.2:

  • Renamed PrioritizedValue to MultiValue, did some rework and added some documentation

Thank you. I will take a look. Definitely seems useful.

Tried

pashkadez@HAB:~$ cd /opt
pashkadez@HAB:/opt$ python3 -m venv habapp
cd habapppashkadez@HAB:/opt$ cd habapp
pashkadez@HAB:/opt/habapp$ source bin/activate
(habapp) pashkadez@HAB:/opt/habapp$ python3 -m pip install --upgrade pip
Requirement already up-to-date: pip in ./lib/python3.7/site-packages (19.2.3)
(habapp) pashkadez@HAB:/opt/habapp$ python3 -m pip install habapp
Collecting habapp
  Using cached https://files.pythonhosted.org/packages/bb/4e/217043a8079a4abaa9d459fce2db5ceec38bcab57a932f97d5539529f940/HABApp-0.7.2-py3-none-any.whl
Requirement already satisfied: aiohttp>=3.5.4 in ./lib/python3.7/site-packages (from habapp) (3.5.4)
Collecting ruamel.yaml>=0.16.1 (from habapp)
  Using cached https://files.pythonhosted.org/packages/fa/90/ecff85a2e9c497e2fa7142496e10233556b5137db5bd46f3f3b006935ca8/ruamel.yaml-0.16.5-py2.py3-none-any.whl
Collecting ujson (from habapp)
  Using cached https://files.pythonhosted.org/packages/16/c4/79f3409bc710559015464e5f49b9879430d8f87498ecdc335899732e5377/ujson-1.35.tar.gz
Requirement already satisfied: paho-mqtt in ./lib/python3.7/site-packages (from habapp) (1.4.0)
Collecting voluptuous>=0.11.7 (from habapp)
  Using cached https://files.pythonhosted.org/packages/24/3b/fe531688c0d9e057fccc0bc9430c0a3d4b90e0d2f015326e659c2944e328/voluptuous-0.11.7.tar.gz
Collecting watchdog (from habapp)
  Using cached https://files.pythonhosted.org/packages/bb/e3/5a55d48a29300160779f0a0d2776d17c1b762a2039b36de528b093b87d5b/watchdog-0.9.0.tar.gz
Collecting aiohttp-sse-client (from habapp)
  Using cached https://files.pythonhosted.org/packages/5f/77/51595510f628065c77a96e7e23ca067b68e57053ca05c32c0c84e1d73789/aiohttp_sse_client-0.1.6-py2.py3-none-any.whl
Requirement already satisfied: async-timeout<4.0,>=3.0 in ./lib/python3.7/site-packages (from aiohttp>=3.5.4->habapp) (3.0.1)
Requirement already satisfied: multidict<5.0,>=4.0 in ./lib/python3.7/site-packages (from aiohttp>=3.5.4->habapp) (4.5.2)
Requirement already satisfied: yarl<2.0,>=1.0 in ./lib/python3.7/site-packages (from aiohttp>=3.5.4->habapp) (1.3.0)
Requirement already satisfied: chardet<4.0,>=2.0 in ./lib/python3.7/site-packages (from aiohttp>=3.5.4->habapp) (3.0.4)
Requirement already satisfied: attrs>=17.3.0 in ./lib/python3.7/site-packages (from aiohttp>=3.5.4->habapp) (19.1.0)
Collecting ruamel.yaml.clib>=0.1.2; platform_python_implementation == "CPython" and python_version < "3.8" (from ruamel.yaml>=0.16.1->habapp)
  Using cached https://files.pythonhosted.org/packages/6a/6c/7b461053ce5be0d7c8b12dcae9a7c10e8012238a00f6fcd98643ee66d2de/ruamel.yaml.clib-0.1.2.tar.gz
Collecting PyYAML>=3.10 (from watchdog->habapp)
  Using cached https://files.pythonhosted.org/packages/e3/e8/b3212641ee2718d556df0f23f78de8303f068fe29cdaa7a91018849582fe/PyYAML-5.1.2.tar.gz
Collecting argh>=0.24.1 (from watchdog->habapp)
  Using cached https://files.pythonhosted.org/packages/06/1c/e667a7126f0b84aaa1c56844337bf0ac12445d1beb9c8a6199a7314944bf/argh-0.26.2-py2.py3-none-any.whl
Collecting pathtools>=0.1.1 (from watchdog->habapp)
  Using cached https://files.pythonhosted.org/packages/e7/7f/470d6fcdf23f9f3518f6b0b76be9df16dcc8630ad409947f8be2eb0ed13a/pathtools-0.1.2.tar.gz
Requirement already satisfied: idna>=2.0 in ./lib/python3.7/site-packages (from yarl<2.0,>=1.0->aiohttp>=3.5.4->habapp) (2.8)
Installing collected packages: ruamel.yaml.clib, ruamel.yaml, ujson, voluptuous, PyYAML, argh, pathtools, watchdog, aiohttp-sse-client, habapp
  Running setup.py install for ruamel.yaml.clib ... error
    ERROR: Command errored out with exit status 1:
     command: /opt/habapp/bin/python3 -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-install-6b49aby7/ruamel.yaml.clib/setup.py'"'"'; __file__='"'"'/tmp/pip-install-6b49aby7/ruamel.yaml.clib/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' install --record /tmp/pip-record-ycfwl097/install-record.txt --single-version-externally-managed --compile --install-headers /opt/habapp/include/site/python3.7/ruamel.yaml.clib
         cwd: /tmp/pip-install-6b49aby7/ruamel.yaml.clib/
    Complete output (23 lines):
    sys.argv ['/tmp/pip-install-6b49aby7/ruamel.yaml.clib/setup.py', 'install', '--record', '/tmp/pip-record-ycfwl097/install-record.txt', '--single-version-externally-managed', '--compile', '--install-headers', '/opt/habapp/include/site/python3.7/ruamel.yaml.clib']
    test compiling test_ruamel_yaml
    running install
    running build
    running build_py
    creating build
    creating build/lib.linux-armv7l-3.7
    creating build/lib.linux-armv7l-3.7/ruamel
    copying .ruamel/__init__.py -> build/lib.linux-armv7l-3.7/ruamel
    creating build/lib.linux-armv7l-3.7/ruamel/yaml
    copying .ruamel/yaml/__init__.py -> build/lib.linux-armv7l-3.7/ruamel/yaml
    creating build/lib.linux-armv7l-3.7/ruamel/yaml/clib
    copying ./__init__.py -> build/lib.linux-armv7l-3.7/ruamel/yaml/clib
    copying ./LICENSE -> build/lib.linux-armv7l-3.7/ruamel/yaml/clib
    running build_ext
    building '_ruamel_yaml' extension
    creating build/temp.linux-armv7l-3.7
    arm-linux-gnueabihf-gcc -pthread -DNDEBUG -g -fwrapv -O2 -Wall -g -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2 -fPIC -I/opt/habapp/include -I/usr/include/python3.7m -c _ruamel_yaml.c -o build/temp.linux-armv7l-3.7/_ruamel_yaml.o
    _ruamel_yaml.c:4:10: fatal error: Python.h: No such file or directory
     #include "Python.h"
              ^~~~~~~~~~
    compilation terminated.
    error: command 'arm-linux-gnueabihf-gcc' failed with exit status 1
    ----------------------------------------
ERROR: Command errored out with exit status 1: /opt/habapp/bin/python3 -u -c 'import sys, setuptools, tokenize; sys.argv[0] = '"'"'/tmp/pip-install-6b49aby7/ruamel.yaml.clib/setup.py'"'"'; __file__='"'"'/tmp/pip-install-6b49aby7/ruamel.yaml.clib/setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' install --record /tmp/pip-record-ycfwl097/install-record.txt --single-version-externally-managed --compile --install-headers /opt/habapp/include/site/python3.7/ruamel.yaml.clib Check the logs for full command output.

dont know how to deal with it… Using Armbian buster on Odroid HC1

Could you run
sudo apt install python3-dev
and then try again?

1 Like

Hi @Spaceman_Spiff

I have enjoyed reading about your project. Any thoughts on using your work as a means of adding extensions (“binding”) for OH? I have a couple of python projects that communicate with OH via MQTT and Homie. It doesn’t really work the way I would like. Reading your documentation, it should be possible to add items to OH, receive control events from OH and update the items from my code - correct?

Mike

Thank you, that helped, would be great you to add this step to the installation guide!

Will do.

Exactly. If you can rewrite your code as a Rule, then all these things are possible.

I getting these errors when using pip to install

Building wheels for collected packages: watchdog, ujson, voluptuous, pathtools
  Building wheel for watchdog (setup.py) ... done
  Stored in directory: C:\Users\mike\AppData\Local\pip\Cache\wheels\61\1d\d0\04cfe495619be2095eb8d89a31c42adb4e42b76495bc8f784c
  Building wheel for ujson (setup.py) ... error
  ERROR: Complete output from command 'c:\program files (x86)\python37-32\python.exe' -u -c 'import setuptools, tokenize;__file__='"'"'C:\\Users\\mike\\AppData\\Local\\Temp\\pip-install-9gihwnks\\ujson\\setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' bdist_wheel -d 'C:\Users\mike\AppData\Local\Temp\pip-wheel-09ykeo7k' --python-tag cp37:
  ERROR: Warning: 'classifiers' should be a list, got type 'filter'
  running bdist_wheel
  running build
  running build_ext
  building 'ujson' extension
  error: Microsoft Visual C++ 14.0 is required. Get it with "Microsoft Visual C++ Build Tools": https://visualstudio.microsoft.com/downloads/
  ----------------------------------------
  ERROR: Failed building wheel for ujson
  Running setup.py clean for ujson
  Building wheel for voluptuous (setup.py) ... done
  Stored in directory: C:\Users\mike\AppData\Local\pip\Cache\wheels\e8\e3\d0\a2d476b9cd09b8f5979789e0aaf07119726a3cfb19ee67aa1e
  Building wheel for pathtools (setup.py) ... done
  Stored in directory: C:\Users\mike\AppData\Local\pip\Cache\wheels\0b\04\79\c3b0c3a0266a3cb4376da31e5bfe8bba0c489246968a68e843
Successfully built watchdog voluptuous pathtools
Failed to build ujson
Installing collected packages: argh, pathtools, watchdog, ujson, aiohttp-sse-client, voluptuous, ruamel.yaml.clib, ruamel.yaml, HABApp
  Running setup.py install for ujson ... error
    ERROR: Complete output from command 'c:\program files (x86)\python37-32\python.exe' -u -c 'import setuptools, tokenize;__file__='"'"'C:\\Users\\mike\\AppData\\Local\\Temp\\pip-install-9gihwnks\\ujson\\setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' install --record 'C:\Users\mike\AppData\Local\Temp\pip-record-btk0fvr5\install-record.txt' --single-version-externally-managed --compile:
    ERROR: Warning: 'classifiers' should be a list, got type 'filter'
    running install
    running build
    running build_ext
    building 'ujson' extension
    error: Microsoft Visual C++ 14.0 is required. Get it with "Microsoft Visual C++ Build Tools": https://visualstudio.microsoft.com/downloads/
    ----------------------------------------
ERROR: Command "'c:\program files (x86)\python37-32\python.exe' -u -c 'import setuptools, tokenize;__file__='"'"'C:\\Users\\mike\\AppData\\Local\\Temp\\pip-install-9gihwnks\\ujson\\setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' install --record 'C:\Users\mike\AppData\Local\Temp\pip-record-btk0fvr5\install-record.txt' --single-version-externally-managed --compile" failed with error code 1 in C:\Users\mike\AppData\Local\Temp\pip-install-9gihwnks\ujson\
WARNING: You are using pip version 19.1.1, however version 19.2.3 is available.
You should consider upgrading via the 'python -m pip install --upgrade pip' command.

Hi Michael,

I also had this issue on Windows.
Please read this: https://habapp.readthedocs.io/en/latest/installation.html#error-message-while-installing-ujson
You must install the MS Visual C++ compiler as described here.

There is also an issue here.

1 Like

@c_wick - that fixed it! Thank you.

@mjcumming: Does everything work as expected? Do you need any help or hints?

I haven’t dug in deep yet - just have played with the examples. My use will be different from what you have solved for - ie. I mostly want to interact with the REST interface to create items, update their state and receive command from OH to change items. Currently I am using MQTT/Homie ie. Python program -> MQTT -> OH and then back. It works but … So if I could have my python program communicate directly to OH that would be a big benefit and reduce complexity.

You can subscribe to the mqtt topics like in the mqtt example and then simply create the items accordingly.

I am just getting into HABApp.

I have a DateTime item in OH that I want to update, and I can’t figure it out.

I can get the item, and display its value, but when I want to update it with post_state it does not then display in the UI.

Here is a snippet:

date_item = self.get_item('HEMLastUpdated')
log.info('%s: current timestamp: %s' % (date_item.name, date_item.state))
dt = datetime.datetime.now()
date_item.post_state(dt)
log.info('%s: updated timestamp to : %s' % (date_item.name, date_item.state))

This is my log output:

[2019-09-27 13:45:37,295] [                   MyRule]     INFO | HEMUpdate: item_state_update: Item HEM_P2 received update 737.201
[2019-09-27 13:45:37,295] [                   MyRule]     INFO | HEMLastUpdated: current timestamp: 2019-09-27 13:45:37.223000-04:00
[2019-09-27 13:45:37,297] [                   MyRule]     INFO | HEMLastUpdated: updated timestamp to : 2019-09-27 13:45:37.223000

But the date/time in the UI does not update. I notice the TZ info is missing, so I tried formatting it as a string, see if passing a string works, but so far no luck.

Any hints on how to update DateTime items in OH?

UPDATE:

OK my stupid, I thought that once I had the item, I could just update it. no I have to post it back to OH. So this works:

self.oh.post_update('HEMLastUpdated', dt)

Sorry for the confusion.

Another question:

How can I tell what kind of item an OH item is? I see isinstance, but there are a limited number of Item types.

For example, how can I tell if an Item is a Number, String or DatetTime Item? These all seem to be just “Items”.

The issue is that some of my Items that display dates/times are strings, and some are DateTime Items.

I have a function in OH that checks the Item type, and if it’s a string returns a timestamp in a specified string format, otherwise it just returns a new DateTime Item, and leaves the formatting up to OH.

Here is my function:

val Functions$Function2<GenericItem, String, String> getTimestamp = [  //function (lambda) to get a timestamp. Returns formatted string and optionally updates an item
    item,
    date_format |
    
    var date_time_format = date_format
    if(date_format == "" || date_format === null) date_time_format = "%1$ta %1$tT" //default format Day Hour:Minute:Seconds
    var String Timestamp = String::format( date_time_format, new Date() )
    if(item != NULL && item !== null) {
        var t = new DateTimeType()
        
        if(item instanceof DateTimeItem) {
            item.postUpdate(t) ////postUpdate(item, t)
            logInfo("Last Update", item.name + " DateTimeItem updated at: " + Timestamp )
            }
        else if(item instanceof StringItem) {
            item.postUpdate(Timestamp) //postUpdate(item, Timestamp)
            logInfo("Last Update", item.name + " StringItem updated at: " + Timestamp )
            }
        else
            logWarn("Last Update", item.name + " is not DateTime or String - not updating")
    }
    Timestamp
    ]

How would I implement this? I’m not sure how to identify it an item is a string or not (as opposed to a DateTime item).

Thanks.