mirror of
https://github.com/vale981/FHEM-Log-Parser
synced 2025-03-04 17:11:38 -05:00
Clean
This commit is contained in:
commit
10860c7dc8
3 changed files with 206 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
*.db
|
||||||
|
__pycache__
|
165
logParser.py
Normal file
165
logParser.py
Normal file
|
@ -0,0 +1,165 @@
|
||||||
|
from sqlalchemy import Column, Integer, String, REAL
|
||||||
|
from sqlalchemy.orm import sessionmaker, scoped_session
|
||||||
|
from sqlalchemy.ext.declarative import declarative_base
|
||||||
|
from sqlalchemy.orm import relationship
|
||||||
|
from sqlalchemy import create_engine
|
||||||
|
from datetime import datetime
|
||||||
|
from math import inf
|
||||||
|
|
||||||
|
engine = create_engine('sqlite:///heaters.db')
|
||||||
|
session_factory = sessionmaker(bind=engine)
|
||||||
|
Session = lambda : scoped_session(session_factory)
|
||||||
|
|
||||||
|
Base = declarative_base()
|
||||||
|
heaters = {}
|
||||||
|
|
||||||
|
class HeaterStatProto():
|
||||||
|
time = Column(Integer, primary_key=True)
|
||||||
|
actuator = Column(Integer)
|
||||||
|
desired_temp = Column(REAL)
|
||||||
|
measured_temp = Column(REAL)
|
||||||
|
|
||||||
|
class Heater(Base):
|
||||||
|
__tablename__ = 'heater_list'
|
||||||
|
name = Column(String, primary_key=True)
|
||||||
|
|
||||||
|
Base.metadata.create_all(engine)
|
||||||
|
|
||||||
|
def getHeater(name):
|
||||||
|
if name in heaters:
|
||||||
|
return heaters[name]
|
||||||
|
|
||||||
|
session = Session()
|
||||||
|
heater = Heater(name=name)
|
||||||
|
session.merge(heater)
|
||||||
|
session.commit()
|
||||||
|
session.close()
|
||||||
|
|
||||||
|
heater = type(name, (Base, HeaterStatProto), {'__tablename__': 'heater_' + name})
|
||||||
|
|
||||||
|
Base.metadata.create_all(engine)
|
||||||
|
heaters[name] = heater
|
||||||
|
return heater
|
||||||
|
|
||||||
|
def getHeaterList():
|
||||||
|
session = Session()
|
||||||
|
heaters = session.query(Heater).all()
|
||||||
|
session.close()
|
||||||
|
return [heater.name for heater in heaters]
|
||||||
|
|
||||||
|
def getHeaterSum(heater, mintime = 0, maxtime = inf):
|
||||||
|
if not heater in getHeaterList():
|
||||||
|
return 'Heater not found!'
|
||||||
|
|
||||||
|
heater = getHeater(heater)
|
||||||
|
session = Session()
|
||||||
|
heaterData = session.query(heater).filter(heater.time > mintime, heater.time < maxtime).order_by(heater.time.asc()).all()
|
||||||
|
session.close()
|
||||||
|
|
||||||
|
totalHeat = 0
|
||||||
|
for h in range(0, len(heaterData) - 1):
|
||||||
|
try:
|
||||||
|
totalHeat += heaterData[h].actuator * (heaterData[h+1].time - heaterData[h].time)
|
||||||
|
except:
|
||||||
|
continue
|
||||||
|
|
||||||
|
return totalHeat
|
||||||
|
|
||||||
|
def getAllHeaterSums(*args, **kwargs):
|
||||||
|
sums = {}
|
||||||
|
for heater in getHeaterList():
|
||||||
|
sums[heater] = getHeaterSum(heater, *args, **kwargs)
|
||||||
|
|
||||||
|
return sums
|
||||||
|
|
||||||
|
class LogParser:
|
||||||
|
# Some constants...
|
||||||
|
def parseLog(self, data):
|
||||||
|
totalLines = len(data)
|
||||||
|
print('Parsing', totalLines, 'lines.')
|
||||||
|
|
||||||
|
heaterData = {}
|
||||||
|
|
||||||
|
lineNum = 0
|
||||||
|
for line in data:
|
||||||
|
lineNum += 1
|
||||||
|
print('\r Progress:', int((lineNum/totalLines)*100), end='')
|
||||||
|
line = line.strip().split(' ')
|
||||||
|
|
||||||
|
if not (len(line) == 4):
|
||||||
|
continue
|
||||||
|
|
||||||
|
timeStamp, name, prop, value = line
|
||||||
|
prop = prop[:-1].replace('-', '_')
|
||||||
|
|
||||||
|
if hasattr(HeaterStatProto, prop):
|
||||||
|
timeStamp = datetime.strptime(timeStamp, '%Y-%m-%d_%H:%M:%S').timestamp()
|
||||||
|
|
||||||
|
if not name in heaterData:
|
||||||
|
heaterData[name] = {}
|
||||||
|
|
||||||
|
if not timeStamp in heaterData[name]:
|
||||||
|
heaterData[name][timeStamp] = {}
|
||||||
|
|
||||||
|
heaterData[name][timeStamp][prop] = value
|
||||||
|
|
||||||
|
print('\n')
|
||||||
|
self.simplify(heaterData)
|
||||||
|
return heaterData
|
||||||
|
|
||||||
|
def simplify(self, data):
|
||||||
|
print('Removing redundant data...')
|
||||||
|
for heater in data.values():
|
||||||
|
lastValue = None
|
||||||
|
for key, value in list(heater.items()):
|
||||||
|
if value == lastValue:
|
||||||
|
del heater[key]
|
||||||
|
continue
|
||||||
|
|
||||||
|
lastValue = value
|
||||||
|
|
||||||
|
def writeHeaters(self, data):
|
||||||
|
print('Writing the parsed data to the Database...')
|
||||||
|
heaters = []
|
||||||
|
|
||||||
|
for heater, heaterHistory in data.items():
|
||||||
|
dbHeater = getHeater(heater)
|
||||||
|
for time, heaterData in heaterHistory.items():
|
||||||
|
heaters.append(dbHeater(time=time, **heaterData))
|
||||||
|
|
||||||
|
session = Session()
|
||||||
|
#session.add_all(heaters)
|
||||||
|
for heater in heaters:
|
||||||
|
try:
|
||||||
|
session.merge(heater)
|
||||||
|
except:
|
||||||
|
print('Could not write: ', heaterx)
|
||||||
|
|
||||||
|
session.commit()
|
||||||
|
session.close()
|
||||||
|
|
||||||
|
def parse(self):
|
||||||
|
try:
|
||||||
|
for logfile in self._logfiles:
|
||||||
|
with open(logfile) as lf:
|
||||||
|
try:
|
||||||
|
print('Reading:', logfile)
|
||||||
|
logdata = lf.readlines()
|
||||||
|
self.writeHeaters(self.parseLog(logdata))
|
||||||
|
|
||||||
|
except (IOError, UnicodeDecodeError) as e:
|
||||||
|
print('Could not read: ', logfile)
|
||||||
|
|
||||||
|
print()
|
||||||
|
|
||||||
|
except EnvironmentError:
|
||||||
|
raise ValueError('Invalid log file!')
|
||||||
|
|
||||||
|
print('Done')
|
||||||
|
|
||||||
|
def __init__(self, logfiles):
|
||||||
|
# Try to read the heater log.
|
||||||
|
self._logData = []
|
||||||
|
self._logfiles = logfiles
|
||||||
|
|
||||||
|
|
39
parseLogs.py
Normal file
39
parseLogs.py
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
import sys
|
||||||
|
import datetime
|
||||||
|
import argparse
|
||||||
|
import logParser
|
||||||
|
from math import inf
|
||||||
|
|
||||||
|
argparser = argparse.ArgumentParser(description='Parse the FHEM logfiles into a Database.')
|
||||||
|
argparser.add_argument('--parse', '-p', nargs='+', help='List of Logfiles to Parse.', required=False, metavar='FILE')
|
||||||
|
argparser.add_argument('--list', '-l', help='List all Heaters in the Database.', action='store_true')
|
||||||
|
argparser.add_argument('--heatAmmount', help='Sum of the actuator value times a time slice.', nargs=1, metavar='HEATER')
|
||||||
|
argparser.add_argument('--allHeatAmmount', help='Get the heat ammount from all known heaters.', action='store_true')
|
||||||
|
argparser.add_argument('--timeSpan', help='The time span for the heatAmmount calculation. Either t1/t2 or both may be supplied.', nargs=1, metavar='t1..t2 | t1 | ..t2')
|
||||||
|
|
||||||
|
# Parse args. Set name to default.
|
||||||
|
args = argparser.parse_args()
|
||||||
|
mintime, maxtime = 0, inf
|
||||||
|
if args.timeSpan:
|
||||||
|
times = args.timeSpan[0].split('..')
|
||||||
|
|
||||||
|
if len(times) < 1 or len(times) > 2:
|
||||||
|
print('Invalid Timespan!')
|
||||||
|
exit(1)
|
||||||
|
elif len(times) == 2:
|
||||||
|
if times[0] == '':
|
||||||
|
maxtime = int(times[1])
|
||||||
|
else:
|
||||||
|
mintime, maxtime = times
|
||||||
|
else:
|
||||||
|
mintime = int(times[0])
|
||||||
|
|
||||||
|
if not args.parse is None:
|
||||||
|
parser = logParser.LogParser(args.parse)
|
||||||
|
parser.parse()
|
||||||
|
elif not args.list is False:
|
||||||
|
print('\n'.join(logParser.getHeaterList()))
|
||||||
|
elif not args.heatAmmount is None:
|
||||||
|
print(logParser.getHeaterSum(args.heatAmmount[0], mintime, maxtime))
|
||||||
|
elif not args.allHeatAmmount is None:
|
||||||
|
print(logParser.getAllHeaterSums(mintime, maxtime))
|
Loading…
Add table
Reference in a new issue