diff --git a/Docker/src/python/tHome/config.py b/Docker/src/python/tHome/config.py
index 3bc7b4e..fb49693 100644
--- a/Docker/src/python/tHome/config.py
+++ b/Docker/src/python/tHome/config.py
@@ -1,67 +1,75 @@
-#===========================================================================
-#
-# Config parsing
-#
-#===========================================================================
+"""Config parsing."""
-__doc__ = """Config parsing.
-"""
+import os
+import glob
+import configparser
from .util import Data
-import ConfigParser
-import glob
-import os.path
-#===========================================================================
-def parse( configDir ):
- # Parse the files. Default xform makes all keys lower case so set
- # it to str to stop that behavior.
- p = ConfigParser.ConfigParser()
- p.optionxform = str
+def parse(configDir):
+ """
+ Parse configuration files from the specified directory.
- files = glob.glob( os.path.join( configDir, "*.conf" ) )
- for f in files:
- p.read( f )
+ Args:
+ configDir (str): The directory containing the configuration files.
- cfg = Data( _config = p )
- for s in p.sections():
- d = Data()
- for o in p.options( s ):
- setattr( d, o, p.get( s, o ) )
+ Returns:
+ Data: Parsed configuration data.
+ """
+ config = configparser.ConfigParser()
+ 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)
-#===========================================================================
-def update( data, secDef ):
- for section, fields in secDef.iteritems():
- if not hasattr( data, section ):
- setattr( data, section, Data() )
+ return parsed_config
- secData = data[section]
- for name, convertFunc, defaultValue in fields:
- if hasattr( secData, name ):
- secData[name] = convertFunc( secData[name] )
+def update(data, secDef):
+ """
+ Update configuration data with default values and type conversion.
- else:
- secData[name] = defaultValue
+ 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):
+ setattr(data, section, Data())
-#===========================================================================
-def toPath( value ):
- """TODO: doc
- """
- if value is None:
- return None
-
- value = str( value )
-
- if "$" in value:
- value = os.path.expandvars( value )
-
- if "~" in value:
- value = os.path.expanduser( value )
+ sec_data = data[section]
+ for name, convert_func, default_value in fields:
+ if hasattr(sec_data, name):
+ sec_data[name] = convert_func(sec_data[name])
+ else:
+ sec_data[name] = default_value
- return value
+def toPath(value):
+ """
+ Convert a path value to its absolute path.
-#===========================================================================
+ Args:
+ value (str): The path value.
+
+ Returns:
+ str: The absolute path.
+ """
+ if value is None:
+ return None
+
+ value = str(value)
+
+ if "$" in value:
+ value = os.path.expandvars(value)
+
+ if "~" in value:
+ value = os.path.expanduser(value)
+
+ return value
\ No newline at end of file
diff --git a/Docker/src/python/tHome/eagle/config.py b/Docker/src/python/tHome/eagle/config.py
index 375aec5..42645e2 100644
--- a/Docker/src/python/tHome/eagle/config.py
+++ b/Docker/src/python/tHome/eagle/config.py
@@ -1,36 +1,41 @@
-#===========================================================================
-#
-# Config file
-#
-#===========================================================================
-
-__doc__ = """Config file parsing.
-"""
+"""Config file parsing."""
from .. import util
from ..util import config as C
-#===========================================================================
-
# Config file section name and defaults.
configEntries = [
- # ( name, converter function, default value )
- C.Entry( "httpPort", int, 22042 ),
- C.Entry( "mqttEnergy", str ),
- C.Entry( "mqttPower", str ),
- C.Entry( "logFile", util.path.expand ),
- C.Entry( "logLevel", int, 20 ), # INFO
- ]
+ # ( name, converter function, default value )
+ C.Entry("httpPort", int, 22042),
+ C.Entry("mqttEnergy", str),
+ C.Entry("mqttPower", str),
+ C.Entry("logFile", util.path.expand),
+ C.Entry("logLevel", int, 20), # INFO
+]
-#===========================================================================
-def parse( configDir, configFile='eagle.py' ):
- return C.readAndCheck( configDir, configFile, configEntries )
+def parse(configDir, configFile='eagle.py'):
+ """
+ Parse the configuration file.
-#===========================================================================
-def log( config, logFile=None ):
- if not logFile:
- logFile = config.logFile
-
- return util.log.get( "eagle", config.logLevel, logFile )
+ 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)
+
+def log(config, logFile=None):
+ """
+ Get the logger configuration.
+
+ 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)
\ No newline at end of file
diff --git a/Docker/src/python/tHome/eagle/get.py b/Docker/src/python/tHome/eagle/get.py
index 91ce6f3..c0e5682 100644
--- a/Docker/src/python/tHome/eagle/get.py
+++ b/Docker/src/python/tHome/eagle/get.py
@@ -1,110 +1,68 @@
from . import config
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 socket
-#==========================================================================
def all():
- # Newlines are required
- xmlCmd = "\nget_device_data\n" \
- "%s\n\n" % ( config.macAddress )
- xmlData = sendXml( xmlCmd )
+ xmlCmd = "\nget_device_data\n" \
+ "%s\n\n" % config.macAddress
+ xmlData = sendXml(xmlCmd)
+ xmlData = "%s" % xmlData
+ root = ET.fromstring(xmlData)
+ return msg.DeviceData(root)
- # Add fake wrapper for parsing list of elements
- xmlData = "%s" % xmlData
- root = ET.fromstring( xmlData )
-
- return DeviceData( root )
-
-#==========================================================================
def device():
- # Newlines are required
- xmlCmd = "\nlist_devices\n\n"
- xmlData = sendXml( xmlCmd )
- root = ET.fromstring( xmlData )
+ xmlCmd = "\nlist_devices\n\n"
+ xmlData = sendXml(xmlCmd)
+ root = ET.fromstring(xmlData)
+ return msg.DeviceInfo(root)
- return msg.DeviceInfo( root )
-
-#==========================================================================
def instant():
- # Newlines are required
- xmlCmd = "\nget_instantaneous_demand\n" \
- "%s\n\n" % ( config.macAddress )
- xmlData = sendXml( xmlCmd )
- root = ET.fromstring( xmlData )
+ xmlCmd = "\nget_instantaneous_demand\n" \
+ "%s\n\n" % config.macAddress
+ xmlData = sendXml(xmlCmd)
+ root = ET.fromstring(xmlData)
+ return msg.InstantaneousDemand(root)
- return msg.InstantaneousDemand( root )
+def history(start):
+ startHex = convert.fromTime(start)
+ xmlCmd = "\nget_history_data\n" \
+ "%s\n%s\n" \
+ "\n" % (config.macAddress, startHex)
+ xmlData = sendXml(xmlCmd)
+ root = ET.fromstring(xmlData)
+ return [msg.Total(child) for child in root]
-#==========================================================================
-def history( start ):
- "start == datetime in utc"
- startHex = convert.fromTime( start )
-
- # Newlines are required
- xmlCmd = "\nget_history_data\n" \
- "%s\n%s\n" \
- "\n" % ( config.macAddress, startHex )
- xmlData = sendXml( xmlCmd )
+def instantHistory(interval):
+ assert interval in ['hour', 'day', 'week']
+ xmlCmd = "\nget_demand_values\n" \
+ "%s\n\n" % config.macAddress
+ xmlData = sendXml(xmlCmd)
+ xmlData = "%s" % xmlData
+ root = ET.fromstring(xmlData)
+ return msg.Reading.xmlToList(root)
- # Add fake wrapper for parsing list of elements
- root = ET.fromstring( xmlData )
+def totalHistory(interval):
+ assert interval in ['day', 'week', 'month', 'year']
+ xmlCmd = "\nget_summation_values\n" \
+ "%s\n\n" % config.macAddress
+ xmlData = sendXml(xmlCmd)
+ xmlData = "%s" % xmlData
+ root = ET.fromstring(xmlData)
+ return msg.Reading.xmlToList(root)
- return [ Total( child ) for child in root ]
-
-#==========================================================================
-def instantHistory( interval ):
- "interval = 'hour', 'day', 'week'"
- assert( interval in [ 'hour', 'day', 'week' ] )
+def sendXml(xmlCmd):
+ sock = socket.create_connection((config.host, config.port))
+ try:
+ sock.send(xmlCmd.encode())
- # Newlines are required
- xmlCmd = "\nget_demand_values\n" \
- "%s\n\n" % ( config.macAddress )
- xmlData = sendXml( xmlCmd )
+ buf = b""
+ while True:
+ s = sock.recv(1024)
+ if not s:
+ break
+ buf += s
+ finally:
+ sock.close()
- # Add fake wrapper for parsing list of elements
- xmlData = "%s" % xmlData
- root = ET.fromstring( xmlData )
-
- return msg.Reading.xmlToList( root )
-
-#==========================================================================
-def totalHistory( interval ):
- "interval = 'day', 'week', 'month', 'year'"
- assert( interval in [ 'day', 'week', 'month', 'year' ] )
-
- # Newlines are required
- xmlCmd = "\nget_summation_values\n" \
- "%s\n\n" % ( config.macAddress )
- xmlData = sendXml( xmlCmd )
-
- # Add fake wrapper for parsing list of elements
- xmlData = "%s" % xmlData
- root = ET.fromstring( xmlData )
-
- return msg.Reading.xmlToList( root )
-
-#==========================================================================
-def sendXml( xmlCmd ):
- sock = socket.create_connection( ( config.host, config.port ) )
- try:
- sock.send( xmlCmd )
-
- buf = ""
- while True:
- s = sock.recv( 1024 )
- if not s:
- break
-
- buf += s
- finally:
- sock.close()
-
- return buf
-
-#==========================================================================
+ return buf.decode()
\ No newline at end of file
diff --git a/Docker/src/python/tHome/eagle/parse.py b/Docker/src/python/tHome/eagle/parse.py
index 3a5c464..c62d6fe 100644
--- a/Docker/src/python/tHome/eagle/parse.py
+++ b/Docker/src/python/tHome/eagle/parse.py
@@ -1,26 +1,20 @@
-#===========================================================================
-#
-# Parse XML messages into an object.
-#
-#===========================================================================
import defusedxml.ElementTree as ET
from . import messages
-#==========================================================================
+def parse(xmlText):
+ """
+ Parse XML messages into an object.
-#
-# <[Message]>...[Message]>
-#
-def parse( xmlText ):
- root = ET.fromstring( xmlText )
- assert( root.tag == "rainforest" )
+ Args:
+ xmlText (str): The XML text to parse.
- child = root[0]
+ Returns:
+ messages.Message: The parsed message object.
+ """
+ root = ET.fromstring(xmlText)
+ assert root.tag == "rainforest"
- msgClass = messages.tagMap.get( child.tag, None )
- if not msgClass:
- return None
+ child = root[0]
- return msgClass( child )
-
-#==========================================================================
+ msgClass = messages.tagMap.get(child.tag, None)
+ return msgClass(child) if msgClass else None
\ No newline at end of file