Refactor code to be more readable #46
@@ -1,55 +1,65 @@
|
|||||||
#===========================================================================
|
"""Config parsing."""
|
||||||
#
|
|
||||||
# Config parsing
|
|
||||||
#
|
|
||||||
#===========================================================================
|
|
||||||
|
|
||||||
__doc__ = """Config parsing.
|
import os
|
||||||
"""
|
import glob
|
||||||
|
import configparser
|
||||||
|
|
||||||
from .util import Data
|
from .util import Data
|
||||||
import ConfigParser
|
|
||||||
import glob
|
|
||||||
import os.path
|
|
||||||
|
|
||||||
#===========================================================================
|
|
||||||
def parse(configDir):
|
def parse(configDir):
|
||||||
# Parse the files. Default xform makes all keys lower case so set
|
"""
|
||||||
# it to str to stop that behavior.
|
Parse configuration files from the specified directory.
|
||||||
p = ConfigParser.ConfigParser()
|
|
||||||
p.optionxform = str
|
|
||||||
|
|
||||||
files = glob.glob( os.path.join( configDir, "*.conf" ) )
|
Args:
|
||||||
for f in files:
|
configDir (str): The directory containing the configuration files.
|
||||||
p.read( f )
|
|
||||||
|
|
||||||
cfg = Data( _config = p )
|
Returns:
|
||||||
for s in p.sections():
|
Data: Parsed configuration data.
|
||||||
d = Data()
|
"""
|
||||||
for o in p.options( s ):
|
config = configparser.ConfigParser()
|
||||||
setattr( d, o, p.get( s, o ) )
|
config.optionxform = str # Prevent keys from being transformed to lowercase
|
||||||
|
|
||||||
setattr( cfg, s, d )
|
config_files = glob.glob(os.path.join(configDir, "*.conf"))
|
||||||
|
for file in config_files:
|
||||||
|
config.read(file)
|
||||||
|
|
||||||
return cfg
|
parsed_config = Data(_config=config)
|
||||||
|
for section in config.sections():
|
||||||
|
section_data = Data()
|
||||||
|
for option in config.options(section):
|
||||||
|
setattr(section_data, option, config.get(section, option))
|
||||||
|
setattr(parsed_config, section, section_data)
|
||||||
|
|
||||||
|
return parsed_config
|
||||||
|
|
||||||
#===========================================================================
|
|
||||||
def update(data, secDef):
|
def update(data, secDef):
|
||||||
for section, fields in secDef.iteritems():
|
"""
|
||||||
|
Update configuration data with default values and type conversion.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
data (Data): Configuration data to be updated.
|
||||||
|
secDef (dict): Dictionary defining sections and their default values and conversion functions.
|
||||||
|
"""
|
||||||
|
for section, fields in secDef.items():
|
||||||
if not hasattr(data, section):
|
if not hasattr(data, section):
|
||||||
setattr(data, section, Data())
|
setattr(data, section, Data())
|
||||||
|
|
||||||
secData = data[section]
|
sec_data = data[section]
|
||||||
for name, convertFunc, defaultValue in fields:
|
for name, convert_func, default_value in fields:
|
||||||
if hasattr( secData, name ):
|
if hasattr(sec_data, name):
|
||||||
secData[name] = convertFunc( secData[name] )
|
sec_data[name] = convert_func(sec_data[name])
|
||||||
|
|
||||||
else:
|
else:
|
||||||
secData[name] = defaultValue
|
sec_data[name] = default_value
|
||||||
|
|
||||||
#===========================================================================
|
|
||||||
def toPath(value):
|
def toPath(value):
|
||||||
"""TODO: doc
|
"""
|
||||||
|
Convert a path value to its absolute path.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
value (str): The path value.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
str: The absolute path.
|
||||||
"""
|
"""
|
||||||
if value is None:
|
if value is None:
|
||||||
return None
|
return None
|
||||||
@@ -63,5 +73,3 @@ def toPath( value ):
|
|||||||
value = os.path.expanduser(value)
|
value = os.path.expanduser(value)
|
||||||
|
|
||||||
return value
|
return value
|
||||||
|
|
||||||
#===========================================================================
|
|
||||||
|
|||||||
@@ -1,17 +1,8 @@
|
|||||||
#===========================================================================
|
"""Config file parsing."""
|
||||||
#
|
|
||||||
# Config file
|
|
||||||
#
|
|
||||||
#===========================================================================
|
|
||||||
|
|
||||||
__doc__ = """Config file parsing.
|
|
||||||
"""
|
|
||||||
|
|
||||||
from .. import util
|
from .. import util
|
||||||
from ..util import config as C
|
from ..util import config as C
|
||||||
|
|
||||||
#===========================================================================
|
|
||||||
|
|
||||||
# Config file section name and defaults.
|
# Config file section name and defaults.
|
||||||
configEntries = [
|
configEntries = [
|
||||||
# ( name, converter function, default value )
|
# ( name, converter function, default value )
|
||||||
@@ -22,15 +13,29 @@ configEntries = [
|
|||||||
C.Entry("logLevel", int, 20), # INFO
|
C.Entry("logLevel", int, 20), # INFO
|
||||||
]
|
]
|
||||||
|
|
||||||
#===========================================================================
|
|
||||||
def parse(configDir, configFile='eagle.py'):
|
def parse(configDir, configFile='eagle.py'):
|
||||||
|
"""
|
||||||
|
Parse the configuration file.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
configDir (str): The directory containing the configuration file.
|
||||||
|
configFile (str): The name of the configuration file.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: The parsed configuration.
|
||||||
|
"""
|
||||||
return C.readAndCheck(configDir, configFile, configEntries)
|
return C.readAndCheck(configDir, configFile, configEntries)
|
||||||
|
|
||||||
#===========================================================================
|
|
||||||
def log(config, logFile=None):
|
def log(config, logFile=None):
|
||||||
if not logFile:
|
"""
|
||||||
logFile = config.logFile
|
Get the logger configuration.
|
||||||
|
|
||||||
return util.log.get( "eagle", config.logLevel, logFile )
|
Args:
|
||||||
|
config (dict): The configuration dictionary.
|
||||||
|
logFile (str): The log file path.
|
||||||
|
|
||||||
#===========================================================================
|
Returns:
|
||||||
|
logger: The logger object.
|
||||||
|
"""
|
||||||
|
logFile = logFile or config['logFile']
|
||||||
|
return util.log.get("eagle", config['logLevel'], logFile)
|
||||||
@@ -1,110 +1,68 @@
|
|||||||
from . import config
|
from . import config
|
||||||
from . import messages as msg
|
from . import messages as msg
|
||||||
#from . import convert
|
|
||||||
#from .DeviceData import DeviceData
|
|
||||||
#from .DeviceInfo import DeviceInfo
|
|
||||||
#from .InstantDemand import InstantDemand
|
|
||||||
#from .Reading import Reading
|
|
||||||
#from .Total import Total
|
|
||||||
import defusedxml.ElementTree as ET
|
import defusedxml.ElementTree as ET
|
||||||
import socket
|
import socket
|
||||||
|
|
||||||
#==========================================================================
|
|
||||||
def all():
|
def all():
|
||||||
# Newlines are required
|
|
||||||
xmlCmd = "<LocalCommand>\n<Name>get_device_data</Name>\n" \
|
xmlCmd = "<LocalCommand>\n<Name>get_device_data</Name>\n" \
|
||||||
"<MacId>%s</MacId>\n</LocalCommand>\n" % ( config.macAddress )
|
"<MacId>%s</MacId>\n</LocalCommand>\n" % config.macAddress
|
||||||
xmlData = sendXml(xmlCmd)
|
xmlData = sendXml(xmlCmd)
|
||||||
|
|
||||||
# Add fake wrapper for parsing list of elements
|
|
||||||
xmlData = "<root>%s</root>" % xmlData
|
xmlData = "<root>%s</root>" % xmlData
|
||||||
root = ET.fromstring(xmlData)
|
root = ET.fromstring(xmlData)
|
||||||
|
return msg.DeviceData(root)
|
||||||
|
|
||||||
return DeviceData( root )
|
|
||||||
|
|
||||||
#==========================================================================
|
|
||||||
def device():
|
def device():
|
||||||
# Newlines are required
|
|
||||||
xmlCmd = "<LocalCommand>\n<Name>list_devices</Name>\n</LocalCommand>\n"
|
xmlCmd = "<LocalCommand>\n<Name>list_devices</Name>\n</LocalCommand>\n"
|
||||||
xmlData = sendXml(xmlCmd)
|
xmlData = sendXml(xmlCmd)
|
||||||
root = ET.fromstring(xmlData)
|
root = ET.fromstring(xmlData)
|
||||||
|
|
||||||
return msg.DeviceInfo(root)
|
return msg.DeviceInfo(root)
|
||||||
|
|
||||||
#==========================================================================
|
|
||||||
def instant():
|
def instant():
|
||||||
# Newlines are required
|
|
||||||
xmlCmd = "<LocalCommand>\n<Name>get_instantaneous_demand</Name>\n" \
|
xmlCmd = "<LocalCommand>\n<Name>get_instantaneous_demand</Name>\n" \
|
||||||
"<MacId>%s</MacId>\n</LocalCommand>\n" % ( config.macAddress )
|
"<MacId>%s</MacId>\n</LocalCommand>\n" % config.macAddress
|
||||||
xmlData = sendXml(xmlCmd)
|
xmlData = sendXml(xmlCmd)
|
||||||
root = ET.fromstring(xmlData)
|
root = ET.fromstring(xmlData)
|
||||||
|
|
||||||
return msg.InstantaneousDemand(root)
|
return msg.InstantaneousDemand(root)
|
||||||
|
|
||||||
#==========================================================================
|
|
||||||
def history(start):
|
def history(start):
|
||||||
"start == datetime in utc"
|
|
||||||
startHex = convert.fromTime(start)
|
startHex = convert.fromTime(start)
|
||||||
|
|
||||||
# Newlines are required
|
|
||||||
xmlCmd = "<LocalCommand>\n<Name>get_history_data</Name>\n" \
|
xmlCmd = "<LocalCommand>\n<Name>get_history_data</Name>\n" \
|
||||||
"<MacId>%s</MacId>\n<StartTime>%s</StartTime>\n" \
|
"<MacId>%s</MacId>\n<StartTime>%s</StartTime>\n" \
|
||||||
"</LocalCommand>\n" % (config.macAddress, startHex)
|
"</LocalCommand>\n" % (config.macAddress, startHex)
|
||||||
xmlData = sendXml(xmlCmd)
|
xmlData = sendXml(xmlCmd)
|
||||||
|
|
||||||
# Add fake wrapper for parsing list of elements
|
|
||||||
root = ET.fromstring(xmlData)
|
root = ET.fromstring(xmlData)
|
||||||
|
return [msg.Total(child) for child in root]
|
||||||
|
|
||||||
return [ Total( child ) for child in root ]
|
|
||||||
|
|
||||||
#==========================================================================
|
|
||||||
def instantHistory(interval):
|
def instantHistory(interval):
|
||||||
"interval = 'hour', 'day', 'week'"
|
assert interval in ['hour', 'day', 'week']
|
||||||
assert( interval in [ 'hour', 'day', 'week' ] )
|
|
||||||
|
|
||||||
# Newlines are required
|
|
||||||
xmlCmd = "<LocalCommand>\n<Name>get_demand_values</Name>\n" \
|
xmlCmd = "<LocalCommand>\n<Name>get_demand_values</Name>\n" \
|
||||||
"<MacId>%s</MacId>\n</LocalCommand>\n" % ( config.macAddress )
|
"<MacId>%s</MacId>\n</LocalCommand>\n" % config.macAddress
|
||||||
xmlData = sendXml(xmlCmd)
|
xmlData = sendXml(xmlCmd)
|
||||||
|
|
||||||
# Add fake wrapper for parsing list of elements
|
|
||||||
xmlData = "<root>%s</root>" % xmlData
|
xmlData = "<root>%s</root>" % xmlData
|
||||||
root = ET.fromstring(xmlData)
|
root = ET.fromstring(xmlData)
|
||||||
|
|
||||||
return msg.Reading.xmlToList(root)
|
return msg.Reading.xmlToList(root)
|
||||||
|
|
||||||
#==========================================================================
|
|
||||||
def totalHistory(interval):
|
def totalHistory(interval):
|
||||||
"interval = 'day', 'week', 'month', 'year'"
|
assert interval in ['day', 'week', 'month', 'year']
|
||||||
assert( interval in [ 'day', 'week', 'month', 'year' ] )
|
|
||||||
|
|
||||||
# Newlines are required
|
|
||||||
xmlCmd = "<LocalCommand>\n<Name>get_summation_values</Name>\n" \
|
xmlCmd = "<LocalCommand>\n<Name>get_summation_values</Name>\n" \
|
||||||
"<MacId>%s</MacId>\n</LocalCommand>\n" % ( config.macAddress )
|
"<MacId>%s</MacId>\n</LocalCommand>\n" % config.macAddress
|
||||||
xmlData = sendXml(xmlCmd)
|
xmlData = sendXml(xmlCmd)
|
||||||
|
|
||||||
# Add fake wrapper for parsing list of elements
|
|
||||||
xmlData = "<root>%s</root>" % xmlData
|
xmlData = "<root>%s</root>" % xmlData
|
||||||
root = ET.fromstring(xmlData)
|
root = ET.fromstring(xmlData)
|
||||||
|
|
||||||
return msg.Reading.xmlToList(root)
|
return msg.Reading.xmlToList(root)
|
||||||
|
|
||||||
#==========================================================================
|
|
||||||
def sendXml(xmlCmd):
|
def sendXml(xmlCmd):
|
||||||
sock = socket.create_connection((config.host, config.port))
|
sock = socket.create_connection((config.host, config.port))
|
||||||
try:
|
try:
|
||||||
sock.send( xmlCmd )
|
sock.send(xmlCmd.encode())
|
||||||
|
|
||||||
buf = ""
|
buf = b""
|
||||||
while True:
|
while True:
|
||||||
s = sock.recv(1024)
|
s = sock.recv(1024)
|
||||||
if not s:
|
if not s:
|
||||||
break
|
break
|
||||||
|
|
||||||
buf += s
|
buf += s
|
||||||
finally:
|
finally:
|
||||||
sock.close()
|
sock.close()
|
||||||
|
|
||||||
return buf
|
return buf.decode()
|
||||||
|
|
||||||
#==========================================================================
|
|
||||||
@@ -1,26 +1,20 @@
|
|||||||
#===========================================================================
|
|
||||||
#
|
|
||||||
# Parse XML messages into an object.
|
|
||||||
#
|
|
||||||
#===========================================================================
|
|
||||||
import defusedxml.ElementTree as ET
|
import defusedxml.ElementTree as ET
|
||||||
from . import messages
|
from . import messages
|
||||||
|
|
||||||
#==========================================================================
|
|
||||||
|
|
||||||
# <rainForest ...>
|
|
||||||
# <[Message]>...</[Message]>
|
|
||||||
# </rainForest>
|
|
||||||
def parse(xmlText):
|
def parse(xmlText):
|
||||||
|
"""
|
||||||
|
Parse XML messages into an object.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
xmlText (str): The XML text to parse.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
messages.Message: The parsed message object.
|
||||||
|
"""
|
||||||
root = ET.fromstring(xmlText)
|
root = ET.fromstring(xmlText)
|
||||||
assert( root.tag == "rainforest" )
|
assert root.tag == "rainforest"
|
||||||
|
|
||||||
child = root[0]
|
child = root[0]
|
||||||
|
|
||||||
msgClass = messages.tagMap.get(child.tag, None)
|
msgClass = messages.tagMap.get(child.tag, None)
|
||||||
if not msgClass:
|
return msgClass(child) if msgClass else None
|
||||||
return None
|
|
||||||
|
|
||||||
return msgClass( child )
|
|
||||||
|
|
||||||
#==========================================================================
|
|
||||||
Reference in New Issue
Block a user