Monitoring Things States with Python Rest API

Using a Python-REST-API for Monitoring Things States

In advance: I am no python crack but searched a solution for creating Things-items and updating the states, too. Just for having a quick accessable overview in the new OpenHab widgets.

The Beginning:

  • create an OH-API-token. Save it or write it down somewhere.
  • think about a semantic group name for your Things-items.

Next step will be, copying the code into a new file into a new file in /openhab/scripts/“filename”.py.

What will happen:

  1. The Things will be fetched an renamed, which is necessary for having the link for creating the Item
  2. The list of Things-Items is compared with the existing Item-list. So just new Thing-Items and new Thing-Item-states will be pushed through HTTP-request.

getthingsitem.py

import requests

from datetime import datetime

#Global Variables

openhabip = 'XXX.XXX.XXX.XXX'

syntax_replacement = {" " : "_", "-" : "_", "ä" : "ae", "ü" : "ue", "ö" : "oe", ".":"_","!":"",":" : "_","(":"_",")":"_"}

timestamp = datetime.now().strftime("%A %d/%m/%Y, %H:%M:%S")

thingitemgroup = 'gThingStates' #you can change the group name, as you like

access_token = 'YOUR OPHAB API TOKEN'

headers = {'accept':'*/*','content-type':'application/json','Authorization': 'Bearer {}'.format(access_token)}

headers_post = {'accept':'*/*','content-type':'text/plain','Authorization': 'Bearer {}'.format(access_token)}

things_req = requests.get('http://'+openhabip+':8080/rest/things', headers=headers)

items_req = requests.get('http://'+openhabip+':8080/rest/items', headers=headers)

def getthings():          #fetching things

  things_arr = []

  things_all = things_req.json()

  for i in range(len(things_all)):

        if things_all[i]["statusInfo"]["status"] :

          things_exp = (things_all[i]["label"]).translate(str.maketrans(syntax_replacement))+"_Thing"

          things_status = (things_all[i]["statusInfo"]["status"])

          things_arr.append({'item' : things_exp , 'state' : things_status})

  return things_arr

def getOHitems():       #fetching OH-Items

  ohitems_arr = []

  ohitems_all = items_req.json()

  for i in range(len(ohitems_all)):

    ohitems_exp = (ohitems_all[i]["name"])

    ohitems_exp_state = (ohitems_all[i]["state"])

    ohitems_arr.append({'item' : ohitems_exp , 'state' : ohitems_exp_state})

  return ohitems_arr

def comparegets():          #comparing lists for adding or updating just new Thing-Items or states. Less API requests, especially while running the script in cron-intervals.

    things_arr = getthings()

    ohitems_arr = getOHitems()

    thing_put = []

    have_2 = {(d['item'], d['state']) for d in ohitems_arr}

    extra = [d for d in things_arr if (d['item'], d['state']) not in have_2]

    print(timestamp)

    if extra == []:

      print("No new Items to add or to update!")

    else:

      print("New items added or updated: ", extra)

      

    for i in range(len(extra)):         #creating new items from new thing and updating states, if changed

        if extra[i]["item"]:

          things_exp = (extra[i]["item"])

          things_status = (extra[i]["state"])

          thing_link = ('http://'+openhabip+':8080/rest/items/'+things_exp)

          thing_put.append({'item' : things_exp , 'state' : things_status, 'link' : thing_link})

          itemtoput_arr = [{'link': 'http://'+openhabip+':8080/rest/items/'+things_exp, 'state': 'null', 'editable': 'true', 'type': 'String', 'name': things_exp, 'label': things_exp, 'category': '', 'tags': [ 'Point' ], 'groupNames': [ thingitemgroup]}]

          newitem_put = requests.put('http://'+openhabip+':8080/rest/items' , json=itemtoput_arr , headers=headers)

          item_post = requests.put('http://'+openhabip+':8080/rest/items/'+things_exp +'/state' , data=things_status , headers=headers_post)

          print(newitem_put)

          print(item_post)

comparegets()

Add the Exec Binding to your instance like e.g.:

UID: exec:command:ExecGetThings
label: ExecGetThings
thingTypeUID: exec:command
configuration:
  transform: REGEX((.*))
  interval: 0
  autorun: false
  command: sudo -u openhab python3 /etc/openhab/scripts/getthingstates.py
  timeout: 30

It is possible to create 5 channels (see OpenHab Exec Binding)

For running the rule th channel id “run” is needed, which sends “ON” to the created Exec Thing.

I am running the script through a rule:

triggers:
  - id: "1"
    configuration:
      cronExpression: 0 0/15 * * * ? *
    type: timer.GenericCronTrigger
conditions: []
actions:
  - inputs: {}
    id: "2"
    configuration:
      itemName: ExecGetThings_Ausfuhrung
      command: ON
    type: core.ItemCommandAction
  - inputs: {}
    id: "3"
    configuration:
      type: application/vnd.openhab.dsl.rule
      script:
        logInfo("GetThingsRule","Neue Things werden gesucht und die States werden aktualisiert!")
    type: script.ScriptAction

Remember setting the py-script name as you choosed in the beginning and place it in the rule where I wrote “getthingstates”.
There is a need to whitelist the command in the Exec Binding in /misc/exec.whitelist .

Result:
In the first execution all Things will be added an the states will be set as String.
In a widget a result after filtering for states !=“ONLINE” could be:

Other Thing-States will be shown as in the Things-UI.
New Things will be added wile running the rule and states will be updated.

If you have suggestions or questions, please feel free. I try to answer.

Hav a nice OH-time!

If you don’t mind using a third party library:
with HABApp it’s really easy to check the Thing state.
That way you don’t have to run it cyclic but can generate a notification as soon as the thing goes e.g. offline.

1 Like

Okay, I see the approach. As I read quickly, I would get rid of the HTTP-requests. On the other hand I have to become more familiar with python. Aswell working the virtual environments (which is possible).
How intense is the system usage running the environment parallel to openhab? HABApp is just grabbing the event channel, okay. But it is a mess of data (I have more than 1500 items). Will there be a lag of time e.g. motion detection? In forwarding commands?
Overall, python rules are more flexible in complex approches, more than DSL-Rules.
I will create a test environment for gaining experience. Perhaps, adapting. I will give it a try.

1 Like

I know this may look a bit pedandic …
You wrote

You do not make use of the executeCommandLine statement instead you use the exec binding.
executeCommandLine does not require whitelisting while the exec binding does.

I changed the phrase :wink:

1 Like

System usage is very low: On my old Odroid C2 it was between <1% and 2% CPU Usage.
I am running all my rules in HABApp and I don’t notice any delay at all from my motion sensor.
It’s possible to measure the round trip time (HABApp → openHAB → HABApp) and it’s typically at around 20-30ms.

If you have troubles or questions you can ask them here or just create a new thread under 3rd party.

It’s the recommended way anyway. If you are running openhabian you can install HABApp through the menu (2B).

It’s a totally different way of creating rules so you have to wrap your head around it in the beginning.
But once you got it it’s easier, faster and less error prone.
If you want to you can also try it on your main machine and connect remotely to your openhab instance.

1 Like

Thanks for response, Its too helpful for me, Really appreciate.

2 Likes