How big is my OpenHab Setup

Hi guys,

I am wondering if there is a nice way to find out how many:

  • items I have
  • things I have
  • rules I have

in a way that I can graph that. Haven’t found something in the forums yet.

I could write a py-script like that to update specific items:

import json
import requests
items = len(requests.get(url = "http://demo.openhab.org:8080/rest/items? 
recursive=false").json())
things = len(requests.get(url = "http://demo.openhab.org:8080/rest/things").json())
print('Anzahl items: ' + str(items))
print('Anzahl things: ' + str(things))

but for rules… well, how would I count rules?

and how can I trigger the update so that it runs after I change “rules, items, things”?

Any ideas?

Sorry, wrong link :wink: trying to find the right on … there is a thread in the forum with instructions and replies about differnt user’s setups.

cannot find the instructions, but that is a nice thread I haven’t seen before :smiley:

Firstly, thanks for this, this is a great “statistics” :slightly_smiling_face:

You can create a rule running this script with the “System started” trigger. This will always get triggered if you update the items, things files…

Also interesting, and for getting your number of items (and possibly things):

And for the amount of rules you could run
grep -rnwc ‘path/to/your/rules/directory’ -e ‘when’

hmm, interesting, but according to the documentation:

I have a lot of rule files, so that would only fit 100% as long as I have at least dummy rules not in every file. But that would not be a problem, so thanks for that!

Yes I think .rules file won’t trigger this, but items file will definitely do (any items file). I think the same happens with .things file if I remember correctly.

Yes, I thought about that, but was not sure about the comments that contain the “word”. Would have to optimize the regex, e.g. the only characters in a line must be “when” and nothing else, no // or /* or other things… that would work. I guess ‘^when’ would work in “most” cases. It’s not perfect though, but I can live with it for now

Something like this for rules?

grep -o '\<rule\>' ./rules/* | wc -l

I know it just counts ‘rule’ word in that folder in all files, so it only works if you dont use the ‘rule’ word anywhere else in your rules.

For counting the things you could use the REST call:
http://myopenhabserver:8080/rest/things
The response is a JSON string containing all things.
Similar would work for items:
http://myopenhabserver:8080/rest/items?recursive=false

Exactly the same in the original post. But what about rules? How can you count rules easily?

If you are using JSR223 or NGRE Rules you can use the REST API the same as Jürgen shows for Things.

For Rules DSL Rules use something like you post above. Pick a word or string of words that are unlikely to occur more than once per rule, grep for it and use wc -l to get the count.

Thanks!
I didn’t had time yet to convert my rules to JSR223, but I’m in the process…

Yes I have tried it, it works from command line, but from a rule it says ‘there is no such directory or file’.

val result2 = executeCommandLine("grep -o '\\<rule\\>' /etc/openhab2/rules/* | wc -l", 5000)

Running as user openhab from command line, works also…

Provide the full path for grep and wc. Replace the spaces with @@ the same as is sometimes required by the Exec binding. If all else fails, put it into a shell script and run the script from OH.

1 Like

Hi guys,
so that little python script is finished, hope you like it:

import requests, sys, glob, re
url_openhab = 'http://openhab2:8080'

items = len(requests.get(url = url_openhab + "/rest/items?recursive=false").json())
requests.post(url = url_openhab + "/rest/items/" + "Items_Count", data = str(items), verify=False) 
print("Items: "+ str(items))

things = len(requests.get(url = url_openhab + "/rest/things").json())
requests.post(url = url_openhab + "/rest/items/" + "Things_Count", data = str(things), verify=False) 
print("Things: "+ str(things))

rules = 0
for fileName in glob.glob("/srv/openhab2-conf/rules/*.rules"):
    with open(fileName, 'r') as file:
        fileContent = file.read()
        fileContent = re.sub(re.compile(r"/\*.*?\*/",re.DOTALL ) ,"" ,fileContent) # remove all occurrences streamed comments (/*COMMENT */) 
        fileContent = re.sub(re.compile(r"//.*?\n" ) ,"" ,fileContent) # remove all occurrence single-line comments (//COMMENT\n ) 
        rules = rules + len(re.findall('rule', fileContent, re.IGNORECASE))

requests.post(url = url_openhab + "/rest/items/" + "Rules_Count", data = str(rules), verify=False) 
print("Rules: "+ str(rules))

in my case, it returns:

Items: 1242
Things: 44
Rules: 224

that I will start graphing as things progress here :slight_smile:

Thanks, I have replaced my code with this, and also cleaned up the code a bit, so it is easier for others to modify (also some copy paste error is there in your code fence on the last line :slight_smile: ):

import requests, sys, glob, re

# Modify these variables to fit your system
url_openhab = 'http://localhost:8080'
thing_item_name = "openHAB_AllThings"
item_item_name = "openHAB_AllItems"
rule_item_name = "openHAB_AllRules"
rule_path = "/etc/openhab2/rules/*.rules"

items = len(requests.get(url = url_openhab + "/rest/items?recursive=false").json())
requests.post(url = url_openhab + "/rest/items/" + item_item_name, data = str(items), verify=False) 
print("Items: "+ str(items))

things = len(requests.get(url = url_openhab + "/rest/things").json())
requests.post(url = url_openhab + "/rest/items/" + thing_item_name, data = str(things), verify=False) 
print("Things: "+ str(things))

rules = 0
for fileName in glob.glob(rule_path):
    with open(fileName, 'r') as file:
        fileContent = file.read()
        fileContent = re.sub(re.compile(r"/\*.*?\*/",re.DOTALL ) ,"" ,fileContent)  # remove all occurrences streamed comments (/*COMMENT */) 
        fileContent = re.sub(re.compile(r"//.*?\n" ) ,"" ,fileContent)              # remove all occurrence single-line comments (//COMMENT\n ) 
        rules = rules + len(re.findall('rule', fileContent, re.IGNORECASE))

requests.post(url = url_openhab + "/rest/items/" + rule_item_name, data = str(rules), verify=False) 
print("Rules: "+ str(rules))

However this says that I have 114 rules, but with grep and wc I posted earlier it says 84. Interesting because it doesn’t even look for comments and other and still it says less rule… I will look into this.

Thanks Kristof,
the

grep -o '\<rule\>' ./rules/* | wc -l

gives me 176 rules - I have not investigated this yet.

Thanks, I will also try to track this down.

The regex expression is not enough in re.findall(). It will also match any string containing ‘rule’ inside, so for example “rules” will also also match this.

So here is my better version, it does have your suggested fix but also counts the ends, whens, thens and takes the lowest counts it finds :slight_smile:

And… I added logging for that, which I kept, logging is good…
And… I started with your version, kind of,
And… I found out how to post code the right way

import requests, logging, sys, glob, re

url_openhab = 'http://openhab2:8080'
path_for_log = '/var/log/openhab2/count_my_stuff.log'
thing_item_name = "Things_Count"
item_item_name = "Items_Count"
rule_item_name = "Rules_Count"
rule_path = "/etc/openhab2/rules/*.rules"

logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger('count_my_stuff')
#logger.setLevel(logging.DEBUG)
fh = logging.FileHandler(path_for_log)
fh.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setFormatter(formatter)
logger.addHandler(fh)


try: 
    items = len(requests.get(url = url_openhab + "/rest/items?recursive=false").json())
    logger.info("found " + str(items) + " Items" )
    requests.post(url = url_openhab + "/rest/items/" + item_item_name, data = str(items), verify=False) 
except: # catch *all* exceptions
    logger.error( sys.exc_info() )

try: 
    things = len(requests.get(url = url_openhab + "/rest/things").json())
    logger.info("found " + str(things) + " Things" )
    requests.post(url = url_openhab + "/rest/items/" + thing_item_name, data = str(things), verify=False) 
except: # catch *all* exceptions
    logger.error( sys.exc_info() )

try:
    rules = 0
    whens = 0
    thens = 0
    ends = 0
    counter = []
    for fileName in glob.glob("/srv/openhab2-conf/rules/*.rules"):
        with open(fileName, 'r') as file:
            
            fileContent = file.read()
            fileContent = re.sub(re.compile(r"/\*.*?\*/",re.DOTALL ) ,"" ,fileContent) # remove all occurrences streamed comments (/*COMMENT */) 
            fileContent = re.sub(re.compile(r"//.*?\n" ) ,"" ,fileContent) # remove all occurrence single-line comments (//COMMENT\n ) 
          
            rules_in_this_file = len(re.findall(r'\brule\b', fileContent, re.IGNORECASE))
            rules = rules + rules_in_this_file
            logger.debug("found " + str(rules_in_this_file) + " rules in file" + fileName)
            
            whens_in_this_file = len(re.findall(r'\bwhen\b', fileContent, re.IGNORECASE))
            whens = whens + whens_in_this_file
            logger.debug("found " + str(whens_in_this_file) + " whens in file" + fileName)

            thens_in_this_file = len(re.findall(r'\bthen\b', fileContent, re.IGNORECASE))
            thens = thens + thens_in_this_file
            logger.debug("found " + str(thens_in_this_file) + " thens in file" + fileName)

            ends_in_this_file = len(re.findall(r'\bend\b', fileContent, re.IGNORECASE))
            ends = ends + ends_in_this_file
            logger.debug("found " + str(ends_in_this_file) + " ends in file" + fileName)
   
    counter.append(rules)
    counter.append(whens)
    counter.append(thens)
    counter.append(ends)
    rules_count = min(counter)
    logger.info("counting " + str(rules_count) + " rules" )
    
    requests.post(url = url_openhab + "/rest/items/" + rule_item_name, data = str(rules_count), verify=False) 
except: # catch *all* exceptions
    logger.error( sys.exc_info() )


Now I have 129 rules

1 Like

Thanks I will try it! However you should have the same amount of rule when then end, right?