Modular sitemap script

I was struggling with a way to big sitemap.
I made a workaround to creates modular sitemap.
My script allows you to create a sitemap-item.

Sitemap name="example"

It will search for a file called “example.sitemap” an inserts all it’s contents instead of the tag.
finally it will create a file named by the name in the sitemap definition of the root-file.
The root element is a file called “main.sitemap” in the folder sitemapparts.

Exmple:
sitemapparts/main.sitemap

sitemap defaultAutoGenerated  label="Home"
{
    Frame label="Wohnraum" icon="firstfloor" {
        Sitemap name="livingroom.sitemap"
    }
}

sitemapparts/livingroom.sitemap

Frame label="Wohnraum" icon="firstfloor" {
    Text item=gTadoBatteryLow visibility=[gTadoBatteryLow==ON]
    Sitemap name="wohnraum/temp" 
    Sitemap name="wohnraum/lstg"
}

sitemapparts/wohnraum/lstg.sitemap

Group    item=gHeizungLstg{
    Text item=HEAT_Wohnzimmer_heating_power     label="Wohnzimmer"
    Text item=HEAT_Esszimmer_heating_power      label="Esszimmer"
    Text item=HEAT_Kueche_heating_power         label="Küche"
    Text item=HEAT_Badezimmer_heating_power     label="Badezimmer"
    Text item=HEAT_Toilette_heating_power       label="Toilette"
    Text item=HEAT_Arbeitszimmer_heating_power  label="Arbeitszimmer"
    Text item=HEAT_Schlafzimmer_heating_power   label="Schlafzimmer"
}

Generated output
sitemaps/defaultAutoGenerated.sitemap.

// Autogenerated sitemap by Sitemapscript located in /etc/openhab2/scripts/watchdir.py
sitemap defaultAutoGenerated  label="Home"
{
    Frame label="Wohnraum" icon="firstfloor" {
        Frame label="Wohnraum" icon="firstfloor" {
            Text item=gTadoBatteryLow visibility=[gTadoBatteryLow==ON]
            //File wohnraum/temp.sitemap doesn't exists. Therefore ignoring it. 
            Group    item=gHeizungLstg{
                Text item=HEAT_Wohnzimmer_heating_power     label="Wohnzimmer"
                Text item=HEAT_Esszimmer_heating_power      label="Esszimmer"
                Text item=HEAT_Kueche_heating_power         label="Küche"
                Text item=HEAT_Badezimmer_heating_power     label="Badezimmer"
                Text item=HEAT_Toilette_heating_power       label="Toilette"
                Text item=HEAT_Arbeitszimmer_heating_power  label="Arbeitszimmer"
                Text item=HEAT_Schlafzimmer_heating_power   label="Schlafzimmer"
            }
        }
    }
}

You can use subfolders. The script will also add whitespaces in front of each row, so that the imported sitemaps will fit to the format.
The export file will be stored as sitemaps/defaultAutoGenerated.sitemap.
There will be now warning before overwriting so take care of your files.

How to:

  1. Create a dir /etc/openhab2/sitemapparts
sudo mkdir /etc/openhab2/sitemapparts
  1. Install depencies systemd and watchdog
sudo pip3 install systemd
sudo pip3 install watchdog
  1. Create the python script below as /etc/openhab2/scripts/watchdir.py
#!/usr/bin/env python
import watchdog.events 
import watchdog.observers 
import time 
import re
import os.path
import logging
from systemd.journal import JournaldLogHandler

#Path to store sitemaps
global inputPath 
inputPath = r"/etc/openhab2/sitemapparts/"
global outputPath 
outputPath = r"/etc/openhab2/sitemaps/"

#Debounce to avoid multiple runs
global lastBuild
lastBuild=0

# get an instance of the logger object this module will use
logger = logging.getLogger(__name__)

# instantiate the JournaldLogHandler to hook into systemd
journald_handler = JournaldLogHandler()

# set a formatter to include the level name
journald_handler.setFormatter(logging.Formatter(
    '[%(levelname)s] %(message)s'
))

# add the journald handler to the current logger
logger.addHandler(journald_handler)

#streamHandler = logging.StreamHandler()
#logger.addHandler(streamHandler)

# optionally set the logging level
logger.setLevel(logging.INFO)

class Handler(watchdog.events.PatternMatchingEventHandler): 
    def __init__(self): 
        # Set the patterns for PatternMatchingEventHandler 
        watchdog.events.PatternMatchingEventHandler.__init__(self, patterns=['*.sitemap'], 
                                                             ignore_directories=True, case_sensitive=False) 

    #if any event in current item hapens
    def on_any_event(self, event):
        global lastBuild
        #and the last item was created minimum a second ago
        if int(time.time())-lastBuild>1:
            logger.info('Change in file "' + str(event.src_path).replace(inputPath,'') + '"')
            #build the sitemap
            buildSitemapFile()

#Builds the Sitemaps file
def buildSitemapFile():
    if not os.path.isfile(inputPath+'main.sitemap'):
        logger.warning('Root file "main.sitemap" does not exist.')
    else:
        content = getFileContent('main')
        #Don't continue if file is empty
        if content is None:
            return
        
        #Set current time to avoud debounce
        global lastBuild
        lastBuild = int(time.time())

        #Search for the name of the sitemap to set the filename
        filename = 'noname.sitemap'
        regex = r"sitemap\s*(\w*)(\s*label=\")?(\w*)?"
        matches = re.finditer(regex, content)
        sitemapname="noname"
        for match in matches:
            filename = match.group(1)+'.sitemap'
            if(match.group(3) !=""):
                sitemapname = match.group(3) + " ("+match.group(1)+")"
            else:
                sitemapname = match.group(1)

        content = "// Autogenerated sitemap by Sitemapscript located in " + os.path.realpath(__file__) + "\n\r" + content

        #write sitemap to path
        f = open(outputPath+filename, "w")
        f.write(content)
        f.close()
        logger.info('wrote sitemap ' + sitemapname + ' to '+outputPath+filename)

# This function reads the content of a sitemapfile.
# filename: the name of the sitemap without the .sitemap
# prespaces: a string to be set before every row to get a nice formatted file
def getFileContent(filename, prespaces=''):
    filename += '.sitemap'
    logger.debug('Processing file: '+filename)
    #If the file doesnt exists leave a comment in the target sitemap
    if not os.path.isfile(inputPath+filename):
        logger.info("File " + filename + " doesn't exists. Therefore ignoring it.")
        return '//File '+ filename + ' doesn\'t exists. Therefore ignoring it.'
    else:
        data = ""
        #Read the target file line by line and extend it by the pre-spaces
        with open(inputPath+filename, 'r') as fp:
            line = fp.readline()
            while line:
                data += prespaces + line
                line = fp.readline()
        
        #If the file was empty retun None
        if data == "":
            return None

        #otherwise search for sitemap items
        regex = r"^([\t ]*)Sitemap\s*name=\"([\\\/\w]*)\""
        matches = re.finditer(regex, data, re.MULTILINE)
        for match in matches:
            #if a sitemap item was found call getFileContent wit the sitemapname and 4 extra spaces
            content = getFileContent(match.group(2),prespaces+'    ')
            #replace the Sitemap item with the filecontent
            if(content is not None):
                data = data.replace(match.group(),content)
            else:
                logger.info("File " + filename + " is empty.")
        return data

if __name__ == "__main__":
    logger.info("Observing directory '" + inputPath + "'.")
    logger.info("Initial Build")
    buildSitemapFile()
    logger.info("Starting watchdog observer")
    event_handler = Handler() 
    observer = watchdog.observers.Observer() 
    observer.schedule(event_handler, path=inputPath, recursive=True) 
    try: 
        observer.start()
        while True: 
            time.sleep(1) 
    except KeyboardInterrupt: 
        observer.stop() 
    observer.join() 
  1. Create a service for the script
sudo nano /lib/systemd/system/sitemapWatchdog.service

The content of the file is

[Unit]
Description=Watchdog and sitemap-generator for /etc/openhab2/sitemapparts
After=multi-user.target

[Service]
Type=simple
ExecStart=/usr/bin/python3 /etc/openhab2/scripts/watchdir.py
WorkingDirectory=/etc/openhab2/sitemapparts
Restart=on-abort
StandardOutput=inherit
StandardError=inherit
User=openhab

[Install]
WantedBy=multi-user.target
  1. Activate the service
sudo chmod 644 /lib/systemd/system/sitemapWatchdog.service
chmod +x /etc/openhab2/scripts/watchdir.py
sudo systemctl daemon-reload
sudo systemctl enable sitemapWatchdog.service
sudo systemctl start sitemapWatchdog.service
  1. Create your sitemapfiles.
2 Likes

I’ve changed some lines in the Python script due to better logging and to avoud Exceptions when linking to an empty sitemap file

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