This my engine (python)
import os
import sys
import datetime
import json
cintIndent = 2
__location__ = ""
def readfile(location , filenamein):
filein = open(os.path.join(location,filenamein) ,"r")
text = filein.readlines()
filein.close()
return text
def processFile(location,filenamein, fileout, prefix = "", intblock = 0, intsublock = 0, j={}, jinja = True):
filein = open(os.path.join(location,filenamein) ,"r")
lines = filein.readlines()
filein.close()
#Check for END
blnKeep = True
sublines = []
for line in lines:
if line[0:3] == "END":
blnKeep = False
if blnKeep:
sublines.append (line)
lines = sublines
#Cleaning to only keep one of the underlying block
if intblock > 0:
currentblock = 0
sublines = []
for line in lines:
if line[0] == "-":
currentblock +=1
if currentblock == intblock and (line [0] == "-" or line [0] == " "):
sublines.append(line)
lines = sublines
if intsublock > 0:
currentblock = 0
sublines = []
for line in lines:
line = line[cintIndent:]
if line[0] == "-":
currentblock +=1
if currentblock == intsublock and (line [0] == "-" or line [0] == " "):
sublines.append(line)
lines = sublines
for line in lines:
if "#include" in line:
remainingline,command = line.split("#include")
recursionfile,j = parseCommand(command.replace("\n",""))
x = j['#block'].split(",")
intblock = int(x[0])
intsublock = int(x[1])
jinja4child = j["#jinja"]
processFile(location, recursionfile.strip(),fileout, prefix + remainingline, intblock,intsublock, j, jinja4child)
else:
if jinja:
proceesedline = replaceLogic(line,j)
else:
proceesedline = line
fileout.write(prefix + proceesedline)
if len(line) == 0 :
fileout.write('\n')
else:
if line[-1] != '\n':
fileout.write('\n')
def replaceLogic(line,j):
#for key in j:
# line = line.replace(key,j[key])
#return line
from jinja2 import Template
tm = Template(line)
newtm = tm.render(j=j) + '\n'
return newtm
def parseCommand(command):
# xxxx.yaml,{'#block': '1,1', 'v1': 145, 'v2': 'abc'}
mylist = command.split(",",1)
file = mylist[0]
if len(mylist) == 1:
mylist.append('{"#block": "0,0"}')
j = json.loads(mylist[1])
j["#block"] = j["#block"] + ",0,0\n"
if not "#jinja" in j:
j["#jinja"] = True
else:
j["#jinja"]= (j["#jinja"] == "True")
return file,j
def main(location, inputfile, outputfull):
print("-" * 80)
print("location : " + location)
print("inputfile : " + inputfile)
print("outputfull: " + outputfull)
print("-"*80)
fileout = open(outputfull,"w")
processFile(location,inputfile,fileout)
fileout.close()
filein = open(outputfull ,"r")
lines = filein.readlines()
filein.close()
now = datetime.datetime.now()
fulltext = "".join(lines)
#pyperclip.copy(fulltext)
print("lines : " + str(len(lines)))
print("Bytes : " + str(len(fulltext)))
print("Timestamp : " + now.strftime('%Y-%m-%d %H:%M:%S'))
print("-"*80)
if __name__ == "__main__":
if len(sys.argv) == 1:
location = os.path.dirname(__file__)
inputfile ="input.yaml"
outputfull = os.path.join(location,"output.yaml")
else:
location = os.path.dirname(sys.argv[1])
inputfile =os.path.basename(sys.argv[1])
outputfull = sys.argv[2]
##FOR DEBUGGING WHEN NEEDED
if 1==2:
location="y:\\development\\Hass.io\\config\\tools\\yamlsensor"
inputfile= "main_binary.yaml"
outputfull = "y:\\development\\Hass.io\\config\\auto_binary_sensor.yaml"
main(location,inputfile , outputfull)
Usage:
python yamlmerge.py main_binary.yaml auto_binary_sensor.yaml
It takes 2 arguments: an input file & an output file
The input file is a yaml file like you want where you can use a new keyword “#include”
The output file is the final output file where the #include has been replaced using potentially jinja2 logic if needed. You can also pass key/value pairs to the #include commands
Example of a simple input file (the main_binary.yaml):
########################################
#
# Trend
#
########################################
- platform: trend
sensors:
#include binary_sensor_trend.yaml,{"#block":"0","location":"salon", "sensor":"sensor.nest_temperature", "#jinja": "True"}
#include binary_sensor_trend.yaml,{"#block":"0","location":"hall", "sensor":"sensor.zigate_00158d00034f8c03_temperature"}
#include binary_sensor_trend.yaml,{"#block":"0","location":"sdb", "sensor":"sensor.zigate_00158d000358edfa_temperature"}
#include binary_sensor_trend.yaml,{"#block":"0","location":"chparents", "sensor":"sensor.zigate_00158d0003590e7a_temperature"}
#include binary_sensor_trend.yaml,{"#block":"0","location":"chmorgane", "sensor":"sensor.zigate_00158d0003a279c2_temperature"}
#include binary_sensor_trend.yaml,{"#block":"0","location":"bureaumorgane", "sensor":"sensor.zigate_00158d0003a27993_temperature"}
#include binary_sensor_trend.yaml,{"#block":"0","location":"bureau", "sensor":"sensor.zigate_00158d0003a28772_temperature"}
and the template for the “binary_sensir_trend.yaml”
{{ j.location }}_temp_rising:
entity_id: {{ j.sensor }}
max_samples: 3
device_class: 'heat'
Paremeters:
#block allows to refer to the “block” you want to insert (this is an easy way if you one files with 10 templates to say the block you want to use, if omitted the full file will be injected)
All the other json are key/value blocks.
Every single row injected will be send to a jinja2 engine allowing to make the replace/computation logic needed.
I used also a special “#jinja” : “False” for rare case where you don’t want to use the jinja logic
The #include is recurside.
I used this to generate a view for horizontal display and another view for vertical display
having only 2 different mains both including the same blocks but in a different “main mayout”
Quick & dirty explanation so apologize in advance