Initial Commit
This commit is contained in:
24
src/python/tHome/eagle/__init__.py
Normal file
24
src/python/tHome/eagle/__init__.py
Normal file
@@ -0,0 +1,24 @@
|
||||
#===========================================================================
|
||||
#
|
||||
# RainForest Eagle Electric meter reading package
|
||||
#
|
||||
#===========================================================================
|
||||
|
||||
__doc__ = """RainForest Eagle electric meter reader.
|
||||
|
||||
This package implements a web server which the RainForest Eagle can use as a cloud service. The Eagle will post data to the this module which parses the XML messages and sends them out as ZeroMQ messages (usually to a tHome.msgHub).
|
||||
|
||||
Logging object name: tHome.eagle
|
||||
"""
|
||||
|
||||
#===========================================================================
|
||||
|
||||
|
||||
#===========================================================================
|
||||
|
||||
from . import config
|
||||
from . import get
|
||||
from . import messages
|
||||
from .parse import parse
|
||||
|
||||
#===========================================================================
|
||||
36
src/python/tHome/eagle/config.py
Normal file
36
src/python/tHome/eagle/config.py
Normal file
@@ -0,0 +1,36 @@
|
||||
#===========================================================================
|
||||
#
|
||||
# Config file
|
||||
#
|
||||
#===========================================================================
|
||||
|
||||
__doc__ = """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
|
||||
]
|
||||
|
||||
#===========================================================================
|
||||
def parse( configDir, configFile='eagle.py' ):
|
||||
return C.readAndCheck( configDir, configFile, configEntries )
|
||||
|
||||
#===========================================================================
|
||||
def log( config, logFile=None ):
|
||||
if not logFile:
|
||||
logFile = config.logFile
|
||||
|
||||
return util.log.get( "eagle", config.logLevel, logFile )
|
||||
|
||||
#===========================================================================
|
||||
110
src/python/tHome/eagle/get.py
Normal file
110
src/python/tHome/eagle/get.py
Normal file
@@ -0,0 +1,110 @@
|
||||
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 xml.etree.ElementTree as ET
|
||||
import socket
|
||||
|
||||
#==========================================================================
|
||||
def all():
|
||||
# Newlines are required
|
||||
xmlCmd = "<LocalCommand>\n<Name>get_device_data</Name>\n" \
|
||||
"<MacId>%s</MacId>\n</LocalCommand>\n" % ( config.macAddress )
|
||||
xmlData = sendXml( xmlCmd )
|
||||
|
||||
# Add fake wrapper for parsing list of elements
|
||||
xmlData = "<root>%s</root>" % xmlData
|
||||
root = ET.fromstring( xmlData )
|
||||
|
||||
return DeviceData( root )
|
||||
|
||||
#==========================================================================
|
||||
def device():
|
||||
# Newlines are required
|
||||
xmlCmd = "<LocalCommand>\n<Name>list_devices</Name>\n</LocalCommand>\n"
|
||||
xmlData = sendXml( xmlCmd )
|
||||
root = ET.fromstring( xmlData )
|
||||
|
||||
return msg.DeviceInfo( root )
|
||||
|
||||
#==========================================================================
|
||||
def instant():
|
||||
# Newlines are required
|
||||
xmlCmd = "<LocalCommand>\n<Name>get_instantaneous_demand</Name>\n" \
|
||||
"<MacId>%s</MacId>\n</LocalCommand>\n" % ( config.macAddress )
|
||||
xmlData = sendXml( xmlCmd )
|
||||
root = ET.fromstring( xmlData )
|
||||
|
||||
return msg.InstantaneousDemand( root )
|
||||
|
||||
#==========================================================================
|
||||
def history( start ):
|
||||
"start == datetime in utc"
|
||||
startHex = convert.fromTime( start )
|
||||
|
||||
# Newlines are required
|
||||
xmlCmd = "<LocalCommand>\n<Name>get_history_data</Name>\n" \
|
||||
"<MacId>%s</MacId>\n<StartTime>%s</StartTime>\n" \
|
||||
"</LocalCommand>\n" % ( config.macAddress, startHex )
|
||||
xmlData = sendXml( xmlCmd )
|
||||
|
||||
# Add fake wrapper for parsing list of elements
|
||||
root = ET.fromstring( xmlData )
|
||||
|
||||
return [ Total( child ) for child in root ]
|
||||
|
||||
#==========================================================================
|
||||
def instantHistory( interval ):
|
||||
"interval = 'hour', 'day', 'week'"
|
||||
assert( interval in [ 'hour', 'day', 'week' ] )
|
||||
|
||||
# Newlines are required
|
||||
xmlCmd = "<LocalCommand>\n<Name>get_demand_values</Name>\n" \
|
||||
"<MacId>%s</MacId>\n</LocalCommand>\n" % ( config.macAddress )
|
||||
xmlData = sendXml( xmlCmd )
|
||||
|
||||
# Add fake wrapper for parsing list of elements
|
||||
xmlData = "<root>%s</root>" % 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 = "<LocalCommand>\n<Name>get_summation_values</Name>\n" \
|
||||
"<MacId>%s</MacId>\n</LocalCommand>\n" % ( config.macAddress )
|
||||
xmlData = sendXml( xmlCmd )
|
||||
|
||||
# Add fake wrapper for parsing list of elements
|
||||
xmlData = "<root>%s</root>" % 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
|
||||
|
||||
#==========================================================================
|
||||
70
src/python/tHome/eagle/messages/Base.py
Normal file
70
src/python/tHome/eagle/messages/Base.py
Normal file
@@ -0,0 +1,70 @@
|
||||
#===========================================================================
|
||||
#
|
||||
# Base class for messages
|
||||
#
|
||||
#===========================================================================
|
||||
import datetime
|
||||
from . import convert
|
||||
|
||||
#==========================================================================
|
||||
class Base:
|
||||
def __init__( self, name, node=None ):
|
||||
self.name = name
|
||||
|
||||
# Copy the attributes.
|
||||
if node is not None:
|
||||
for child in node:
|
||||
setattr( self, child.tag, child.text )
|
||||
|
||||
# Convert hex values to int and float.
|
||||
convert.hexKeys( self, self._numHexKeys, float )
|
||||
convert.hexKeys( self, self._intHexKeys, int )
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
def msgDict( self ):
|
||||
assert( self._jsonKeys )
|
||||
|
||||
msg = {}
|
||||
for key in self._jsonKeys:
|
||||
if hasattr( self, key ):
|
||||
msg[key] = getattr( self, key )
|
||||
|
||||
if hasattr( self, "TimeUnix" ):
|
||||
msg["Time"] = self.TimeUnix
|
||||
|
||||
return msg
|
||||
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
def _format( self, indent=3 ):
|
||||
i = " "*indent
|
||||
s = "%s(\n" % self.name
|
||||
|
||||
for key in dir( self ):
|
||||
if key[0] == "_":
|
||||
continue
|
||||
|
||||
v = getattr( self, key )
|
||||
if callable( v ):
|
||||
continue
|
||||
|
||||
if hasattr( v, "_format" ):
|
||||
s += "%s%s : %s,\n" % ( i, key, v._format( indent+3 ) )
|
||||
elif isinstance( v, str ):
|
||||
s += "%s%s : '%s',\n" % ( i, key, v )
|
||||
else:
|
||||
s += "%s%s : %s,\n" % ( i, key, v )
|
||||
|
||||
s += "%s)" % i
|
||||
return s
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
def __str__( self ):
|
||||
return self._format()
|
||||
|
||||
def __repr__( self ):
|
||||
return self.__str__()
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
|
||||
#==========================================================================
|
||||
87
src/python/tHome/eagle/messages/BlockPriceDetail.py
Normal file
87
src/python/tHome/eagle/messages/BlockPriceDetail.py
Normal file
@@ -0,0 +1,87 @@
|
||||
#===========================================================================
|
||||
#
|
||||
# BlockPriceDetail Message
|
||||
#
|
||||
#===========================================================================
|
||||
from .Base import Base
|
||||
from . import convert
|
||||
|
||||
#==========================================================================
|
||||
class BlockPriceDetail ( Base ):
|
||||
"""Block price detail message
|
||||
|
||||
After construction, will have the following attributes:
|
||||
|
||||
DeviceMacId int
|
||||
MeterMacId int
|
||||
TimeStamp float (UTC sec past 1-JAN-2000 00:00)
|
||||
CurrentStart
|
||||
CurrentDuration
|
||||
BlockPeriodConsumption
|
||||
BlockPeriodConsumptionMultiplier
|
||||
BlockPeriodConsumptionDivisor
|
||||
NumberOfBlocks
|
||||
Multiplier
|
||||
Divisor
|
||||
Currency
|
||||
TrailingDigits
|
||||
|
||||
Time datetime UTC time stamp
|
||||
TimeUnix float (UTC sec past 1-JAN-1970 00:00)
|
||||
Consumption
|
||||
|
||||
Sample:
|
||||
<BlockPriceDetail>
|
||||
<DeviceMacId>0xd8d5b9000000103f</DeviceMacId>
|
||||
<MeterMacId>0x000781000086d0fe</MeterMacId>
|
||||
<TimeStamp>0x1c531d6b</TimeStamp>
|
||||
<CurrentStart>0x00000000</CurrentStart>
|
||||
<CurrentDuration>0x0000</CurrentDuration>
|
||||
<BlockPeriodConsumption>0x0000000000231c38</BlockPeriodConsumption>
|
||||
<BlockPeriodConsumptionMultiplier>0x00000001</BlockPeriodConsumptionMultiplier>
|
||||
<BlockPeriodConsumptionDivisor>0x000003e8</BlockPeriodConsumptionDivisor>
|
||||
<NumberOfBlocks>0x00</NumberOfBlocks>
|
||||
<Multiplier>0x00000001</Multiplier>
|
||||
<Divisor>0x00000001</Divisor>
|
||||
<Currency>0x0348</Currency>
|
||||
<TrailingDigits>0x00</TrailingDigits>
|
||||
</BlockPriceDetail>
|
||||
"""
|
||||
|
||||
# Hex keys turn into floats or ints. Taken care of automatically
|
||||
# in Base.__init__().
|
||||
_intHexKeys = [ "DeviceMacId", "MeterMacId", "NumberOfBlocks", "Currency",
|
||||
"TrailingDigits", ]
|
||||
_numHexKeys = [ "TimeStamp", "CurrentStart", "CurrentDuration",
|
||||
"BlockPeriodConsumption", "BlockPeriodConsumptionMultiplier",
|
||||
"BlockPeriodConsumptionDivisor", "Multiplier", "Divisor" ]
|
||||
|
||||
_jsonKeys = [ "DeviceMacid", "MeterMacId", "Consumption" ]
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
def __init__( self, node ):
|
||||
assert( node.tag == "BlockPriceDetail" )
|
||||
Base.__init__( self, "BlockPriceDetail", node )
|
||||
|
||||
# Convert a 0 value to 1 (special case).
|
||||
convert.zeroToOne( self, [ "Multiplier", "Divisor" ] )
|
||||
convert.zeroToOne( self, [ "BlockPeriodConsumptionMultiplier",
|
||||
"BlockPeriodConsumptionDivisor" ] )
|
||||
|
||||
self.Consumption = convert.toValue( self.BlockPeriodConsumption,
|
||||
self.BlockPeriodConsumptionMultiplier,
|
||||
self.BlockPeriodConsumptionDivisor )
|
||||
|
||||
convert.time( self, "Time", "TimeUnix", self.TimeStamp )
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
def jsonMsg( self ):
|
||||
return {
|
||||
"MacId" : self.DeviceMacId,
|
||||
"Time" : self.TimeUnix,
|
||||
"Consumption" : self.Consumption,
|
||||
}
|
||||
|
||||
#==========================================================================
|
||||
|
||||
|
||||
78
src/python/tHome/eagle/messages/CurrentSummation.py
Normal file
78
src/python/tHome/eagle/messages/CurrentSummation.py
Normal file
@@ -0,0 +1,78 @@
|
||||
#===========================================================================
|
||||
#
|
||||
# CurrentSummation Message
|
||||
#
|
||||
#===========================================================================
|
||||
from .Base import Base
|
||||
from . import convert
|
||||
|
||||
#==========================================================================
|
||||
class CurrentSummation ( Base ):
|
||||
"""Current summation message
|
||||
|
||||
After construction, will have the following attributes:
|
||||
|
||||
DeviceMacId int
|
||||
MeterMacId int
|
||||
TimeStamp float (UTC sec past 1-JAN-2000 00:00)
|
||||
SummationDelivered float (utility->user)
|
||||
SummationReceived float (user->utility)
|
||||
Multiplier float
|
||||
Divisor float
|
||||
DigitsRight int
|
||||
DigitsLeft int
|
||||
SuppressLeadingZero str
|
||||
|
||||
Consumed float in kWh (utility->user)
|
||||
Produced float in kWh (user->utility)
|
||||
Time datetime UTC time stamp
|
||||
TimeUnix float (UTC sec past 1-JAN-1970 00:00)
|
||||
|
||||
Sample:
|
||||
|
||||
NOTE: Socket API uses CurrentSummation, uploader (cloud) API uses
|
||||
CurrentSummationDelivered. Both are fine.
|
||||
|
||||
<CurrentSummationDelivered>
|
||||
<DeviceMacId>0xd8d5b9000000103f</DeviceMacId>
|
||||
<MeterMacId>0x000781000086d0fe</MeterMacId>
|
||||
<TimeStamp>0x1c531e54</TimeStamp>
|
||||
<SummationDelivered>0x0000000001321a5f</SummationDelivered>
|
||||
<SummationReceived>0x00000000003f8240</SummationReceived>
|
||||
<Multiplier>0x00000001</Multiplier>
|
||||
<Divisor>0x000003e8</Divisor>
|
||||
<DigitsRight>0x01</DigitsRight>
|
||||
<DigitsLeft>0x06</DigitsLeft>
|
||||
<SuppressLeadingZero>Y</SuppressLeadingZero>
|
||||
</CurrentSummationDelivered>
|
||||
"""
|
||||
|
||||
# Hex keys turn into floats or ints. Taken care of automatically
|
||||
# in Base.__init__().
|
||||
_intHexKeys = [ "DeviceMacId", "MeterMacId", "DigitsRight", "DigitsLeft" ]
|
||||
_numHexKeys = [ "TimeStamp", "SummationDelivered", "SummationReceived",
|
||||
"Multiplier", "Divisor" ]
|
||||
|
||||
_jsonKeys = [ "DeviceMacid", "MeterMacId", "Consumed", "Produced" ]
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
def __init__( self, node ):
|
||||
assert( node.tag == "CurrentSummation" or
|
||||
node.tag == "CurrentSummationDelivered" )
|
||||
Base.__init__( self, "CurrentSummation", node )
|
||||
|
||||
# Convert a 0 value to 1 (special case).
|
||||
convert.zeroToOne( self, [ "Multiplier", "Divisor" ] )
|
||||
|
||||
self.Consumed = convert.toValue( self.SummationDelivered,
|
||||
self.Multiplier, self.Divisor )
|
||||
self.Produced = convert.toValue( self.SummationReceived,
|
||||
self.Multiplier, self.Divisor )
|
||||
|
||||
convert.time( self, "Time", "TimeUnix", self.TimeStamp )
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
|
||||
#==========================================================================
|
||||
|
||||
|
||||
59
src/python/tHome/eagle/messages/DeviceInfo.py
Normal file
59
src/python/tHome/eagle/messages/DeviceInfo.py
Normal file
@@ -0,0 +1,59 @@
|
||||
#===========================================================================
|
||||
#
|
||||
# DeviceInfo Message
|
||||
#
|
||||
#===========================================================================
|
||||
from .Base import Base
|
||||
|
||||
#==========================================================================
|
||||
class DeviceInfo ( Base ):
|
||||
"""Network info message
|
||||
|
||||
After construction, will have the following attributes:
|
||||
|
||||
DeviceMacId int
|
||||
InstallCode int
|
||||
LinkKey int
|
||||
FWVersion str
|
||||
HWVersion str
|
||||
ImageType int
|
||||
Manufacturer str
|
||||
ModelId str
|
||||
DateCode str
|
||||
Port str
|
||||
|
||||
Sample:
|
||||
|
||||
<DeviceInfo>
|
||||
<DeviceMacId>0xd8d5b9000000103f</DeviceMacId>
|
||||
<InstallCode>0x8ba7f1dee6c4f5cc</InstallCode>
|
||||
<LinkKey>0x2b26f9124113b1e2b317d402ed789a47</LinkKey>
|
||||
<FWVersion>1.4.47 (6798)</FWVersion>
|
||||
<HWVersion>1.2.3</HWVersion>
|
||||
<ImageType>0x1301</ImageType>
|
||||
<Manufacturer>Rainforest Automation, Inc.</Manufacturer>
|
||||
<ModelId>Z109-EAGLE</ModelId>
|
||||
<DateCode>2013103023220630</DateCode>
|
||||
<Port>/dev/ttySP0</Port>
|
||||
</DeviceInfo>
|
||||
"""
|
||||
|
||||
# Hex keys turn into floats or ints. Taken care of automatically
|
||||
# in Base.__init__().
|
||||
_numHexKeys = []
|
||||
_intHexKeys = [ "DeviceMacId", "InstallCode", "LinkKey", "ImageType" ]
|
||||
|
||||
_jsonKeys = [ "DeviceMacid", "InstallCode", "LinkKey", "FWVersion",
|
||||
"HWVersion", "ImageType", "Manufacturer", "ModelId",
|
||||
"DateCode", "Port" ]
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
def __init__( self, node ):
|
||||
assert( node.tag == "DeviceInfo" )
|
||||
Base.__init__( self, "DeviceInfo", node )
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
|
||||
#==========================================================================
|
||||
|
||||
|
||||
53
src/python/tHome/eagle/messages/FastPollStatus.py
Normal file
53
src/python/tHome/eagle/messages/FastPollStatus.py
Normal file
@@ -0,0 +1,53 @@
|
||||
#===========================================================================
|
||||
#
|
||||
# FastPollStatus Message
|
||||
#
|
||||
#===========================================================================
|
||||
from .Base import Base
|
||||
from . import convert
|
||||
|
||||
#==========================================================================
|
||||
class FastPollStatus ( Base ):
|
||||
"""Fast polling status message
|
||||
|
||||
After construction, will have the following attributes:
|
||||
|
||||
DeviceMacId int
|
||||
CoordMacId int
|
||||
Frequency float (sec)
|
||||
EndTime float (UTC sec past 1-JAN-2000 00:00)
|
||||
|
||||
End datetime UTC time stamp
|
||||
EndUnix float (UTC sec past 1-JAN-1970 00:00)
|
||||
|
||||
Sample:
|
||||
|
||||
<FastPollStatus>
|
||||
<DeviceMacId>0xd8d5b9000000103f</DeviceMacId>
|
||||
<MeterMacId>0x000781000086d0fe</MeterMacId>
|
||||
<Frequency>0x00</Frequency>
|
||||
<EndTime>0xFFFFFFFF</EndTime>
|
||||
</FastPollStatus>
|
||||
"""
|
||||
|
||||
# Hex keys turn into floats or ints. Taken care of automatically
|
||||
# in Base.__init__().
|
||||
_numHexKeys = [ "Frequency", "EndTime" ]
|
||||
_intHexKeys = [ "DeviceMacId", "MeterMacId" ]
|
||||
|
||||
_jsonKeys = [ "DeviceMacid", "Frequency" ]
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
def __init__( self, node ):
|
||||
"""node == xml ETree node
|
||||
"""
|
||||
assert( node.tag == "FastPollStatus" )
|
||||
Base.__init__( self, "FastPollStatus", node )
|
||||
|
||||
convert.time( self, "End", "EndUnix", self.EndTime )
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
|
||||
#==========================================================================
|
||||
|
||||
|
||||
74
src/python/tHome/eagle/messages/InstantaneousDemand.py
Normal file
74
src/python/tHome/eagle/messages/InstantaneousDemand.py
Normal file
@@ -0,0 +1,74 @@
|
||||
#===========================================================================
|
||||
#
|
||||
# InstantaneousDemand Message
|
||||
#
|
||||
#===========================================================================
|
||||
from .Base import Base
|
||||
from . import convert
|
||||
|
||||
#==========================================================================
|
||||
class InstantaneousDemand ( Base ):
|
||||
"""Instantaneous demand message
|
||||
|
||||
After construction, will have the following attributes:
|
||||
|
||||
DeviceMacId int
|
||||
MeterMacId int
|
||||
TimeStamp float (UTC sec past 1-JAN-2000 00:00)
|
||||
Demand float in Watt (may be negative)
|
||||
Multiplier float
|
||||
Divisor float
|
||||
DigitsRight int
|
||||
DigitsLeft int
|
||||
SuppressLeadingZero str
|
||||
|
||||
Power float in kWatt (may be negative)
|
||||
Time datetime UTC time stamp
|
||||
TimeUnix float (UTC sec past 1-JAN-1970 00:00)
|
||||
|
||||
Sample:
|
||||
|
||||
<InstantaneousDemand>
|
||||
<DeviceMacId>0xd8d5b9000000103f</DeviceMacId>
|
||||
<MeterMacId>0x000781000086d0fe</MeterMacId>
|
||||
<TimeStamp>0x1c531d48</TimeStamp>
|
||||
<Demand>0x00032d</Demand>
|
||||
<Multiplier>0x00000001</Multiplier>
|
||||
<Divisor>0x000003e8</Divisor>
|
||||
<DigitsRight>0x03</DigitsRight>
|
||||
<DigitsLeft>0x06</DigitsLeft>
|
||||
<SuppressLeadingZero>Y</SuppressLeadingZero>
|
||||
</InstantaneousDemand>
|
||||
|
||||
plus:
|
||||
Time : datetime object
|
||||
Power : intantaneous power reading
|
||||
"""
|
||||
|
||||
# Hex keys turn into floats or ints. Taken care of automatically
|
||||
# in Base.__init__().
|
||||
_intHexKeys = [ "DeviceMacId", "MeterMacId", "DigitsRight", "DigitsLeft" ]
|
||||
_numHexKeys = [ "Demand", "Multiplier", "Divisor", "TimeStamp" ]
|
||||
|
||||
_jsonKeys = [ "DeviceMacid", "MeterMacId", "Power" ]
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
def __init__( self, node ):
|
||||
assert( node.tag == "InstantaneousDemand" )
|
||||
Base.__init__( self, "InstantaneousDemand", node )
|
||||
|
||||
# Convert a 0 value to 1 (special case).
|
||||
convert.zeroToOne( self, [ "Multiplier", "Divisor" ] )
|
||||
|
||||
# Handle the signed demand field.
|
||||
self.Demand = convert.toSigned4( self.Demand )
|
||||
|
||||
self.Power = convert.toValue( self.Demand, self.Multiplier, self.Divisor )
|
||||
|
||||
convert.time( self, "Time", "TimeUnix", self.TimeStamp )
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
|
||||
#==========================================================================
|
||||
|
||||
|
||||
69
src/python/tHome/eagle/messages/MessageCluster.py
Normal file
69
src/python/tHome/eagle/messages/MessageCluster.py
Normal file
@@ -0,0 +1,69 @@
|
||||
#===========================================================================
|
||||
#
|
||||
# MessageCluster Message
|
||||
#
|
||||
#===========================================================================
|
||||
from .Base import Base
|
||||
from . import convert
|
||||
|
||||
#==========================================================================
|
||||
class MessageCluster ( Base ):
|
||||
"""Message cluster message
|
||||
|
||||
After construction, will have the following attributes:
|
||||
|
||||
DeviceMacId int
|
||||
MeterMacId int
|
||||
TimeStamp float (UTC sec past 1-JAN-2000 00:00)
|
||||
Id int
|
||||
Text str
|
||||
Priority str
|
||||
StartTime float (UTC sec past 1-JAN-2000 00:00)
|
||||
Duration float
|
||||
ConfirmationRequired str
|
||||
Confirmed str
|
||||
Queue str
|
||||
|
||||
Time datetime UTC time stamp
|
||||
TimeUnix float (UTC sec past 1-JAN-1970 00:00)
|
||||
Start datetime UTC time stamp
|
||||
StartUnix float (UTC sec past 1-JAN-1970 00:00)
|
||||
|
||||
Sample:
|
||||
|
||||
<MessageCluster>
|
||||
<DeviceMacId>0xd8d5b9000000103f</DeviceMacId>
|
||||
<MeterMacId>0x000781000086d0fe</MeterMacId>
|
||||
<TimeStamp></TimeStamp>
|
||||
<Id></Id>
|
||||
<Text></Text>
|
||||
<Priority></Priority>
|
||||
<StartTime></StartTime>
|
||||
<Duration></Duration>
|
||||
<ConfirmationRequired>N</ConfirmationRequired>
|
||||
<Confirmed>N</Confirmed>
|
||||
<Queue>Active</Queue>
|
||||
</MessageCluster>
|
||||
"""
|
||||
|
||||
# Hex keys turn into floats or ints. Taken care of automatically
|
||||
# in Base.__init__().
|
||||
_intHexKeys = [ "DeviceMacId", "MeterMacId", "Id" ]
|
||||
_numHexKeys = [ "TimeStamp", "StartTime", "Duration" ]
|
||||
|
||||
_jsonKeys = [ "DeviceMacid", "MeterMacId", "Id", "Text", "Priority",
|
||||
"Duration", "StartTime", "Queue" ]
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
def __init__( self, node ):
|
||||
assert( node.tag == "MessageCluster" )
|
||||
Base.__init__( self, "MessageCluster", node )
|
||||
|
||||
convert.time( self, "Time", "TimeUnix", self.TimeStamp )
|
||||
convert.time( self, "Start", "StartUnix", self.StartTime )
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
|
||||
#==========================================================================
|
||||
|
||||
|
||||
55
src/python/tHome/eagle/messages/MeterInfo.py
Normal file
55
src/python/tHome/eagle/messages/MeterInfo.py
Normal file
@@ -0,0 +1,55 @@
|
||||
#===========================================================================
|
||||
#
|
||||
# MeterInfo Message
|
||||
#
|
||||
#===========================================================================
|
||||
from .Base import Base
|
||||
|
||||
#==========================================================================
|
||||
class MeterInfo ( Base ):
|
||||
"""Network info message
|
||||
|
||||
After construction, will have the following attributes:
|
||||
|
||||
DeviceMacId int
|
||||
CoordMacId int
|
||||
Type str
|
||||
Nickname str
|
||||
Optional:
|
||||
Account str
|
||||
Auth str
|
||||
Host str
|
||||
Enabled str
|
||||
|
||||
Sample:
|
||||
<MeterInfo>
|
||||
<DeviceMacId>0xd8d5b9000000103f</DeviceMacId>
|
||||
<MeterMacId>0x000781000086d0fe</MeterMacId>
|
||||
<Type>0x0000</Type>
|
||||
<Nickname></Nickname>
|
||||
<Account></Account>
|
||||
<Auth></Auth>
|
||||
<Host></Host>
|
||||
<Enabled>Y</Enabled>
|
||||
</MeterInfo>
|
||||
"""
|
||||
|
||||
# Hex keys turn into floats or ints. Taken care of automatically
|
||||
# in Base.__init__().
|
||||
_numHexKeys = []
|
||||
_intHexKeys = [ "DeviceMacId", "CoordMacId" ]
|
||||
|
||||
_jsonKeys = [ "DeviceMacid", "Type", "Enabled" ]
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
def __init__( self, node ):
|
||||
"""node == xml ETree node
|
||||
"""
|
||||
assert( node.tag == "MeterInfo" )
|
||||
Base.__init__( self, "MeterInfo", node )
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
|
||||
#==========================================================================
|
||||
|
||||
|
||||
63
src/python/tHome/eagle/messages/NetworkInfo.py
Normal file
63
src/python/tHome/eagle/messages/NetworkInfo.py
Normal file
@@ -0,0 +1,63 @@
|
||||
#===========================================================================
|
||||
#
|
||||
# NetworkInfo Message
|
||||
#
|
||||
#===========================================================================
|
||||
from .Base import Base
|
||||
|
||||
#==========================================================================
|
||||
class NetworkInfo ( Base ):
|
||||
"""Network info message
|
||||
|
||||
After construction, will have the following attributes:
|
||||
|
||||
DeviceMacId int
|
||||
CoordMacId int
|
||||
Status str
|
||||
LinkStrength int
|
||||
Optional:
|
||||
Description str
|
||||
ExtPanId int
|
||||
Channel int
|
||||
ShortAddr int
|
||||
|
||||
Sample:
|
||||
|
||||
<NetworkInfo>
|
||||
<DeviceMacId>0xd8d5b9000000103f</DeviceMacId>
|
||||
<CoordMacId>0x000781000086d0fe</CoordMacId>
|
||||
<Status>Connected</Status>
|
||||
<Description>Successfully Joined</Description>
|
||||
<ExtPanId>0x000781000086d0fe</ExtPanId>
|
||||
<Channel>20</Channel>
|
||||
<ShortAddr>0xe1aa</ShortAddr>
|
||||
<LinkStrength>0x64</LinkStrength>
|
||||
</NetworkInfo>
|
||||
"""
|
||||
|
||||
# Hex keys turn into floats or ints. Taken care of automatically
|
||||
# in Base.__init__().
|
||||
_numHexKeys = []
|
||||
_intHexKeys = [ "DeviceMacId", "CoordMacId", "ExtPanId", "ShortAddr",
|
||||
"StatusCode", "LinkStrength" ]
|
||||
|
||||
_jsonKeys = [ "DeviceMacid", "Status", "LinkStrength", "Description",
|
||||
"Channel" ]
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
def __init__( self, node ):
|
||||
"""node == xml ETree node
|
||||
"""
|
||||
assert( node.tag == "NetworkInfo" )
|
||||
Base.__init__( self, "NetworkInfo", node )
|
||||
|
||||
# Convert channel string to integer.
|
||||
if hasattr( self, "Channel" ):
|
||||
self.Channel = int( self.Channel )
|
||||
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
|
||||
#==========================================================================
|
||||
|
||||
|
||||
75
src/python/tHome/eagle/messages/PriceCluster.py
Normal file
75
src/python/tHome/eagle/messages/PriceCluster.py
Normal file
@@ -0,0 +1,75 @@
|
||||
#===========================================================================
|
||||
#
|
||||
# Message
|
||||
#
|
||||
#===========================================================================
|
||||
from .Base import Base
|
||||
from . import convert
|
||||
|
||||
#==========================================================================
|
||||
class PriceCluster ( Base ):
|
||||
"""Price cluster message
|
||||
|
||||
After construction, will have the following attributes:
|
||||
|
||||
DeviceMacId int
|
||||
MeterMacId int
|
||||
TimeStamp float (UTC sec past 1-JAN-2000 00:00)
|
||||
Price float
|
||||
Currency int
|
||||
TrailingDigits int
|
||||
Tier int
|
||||
StartTime float (UTC sec past 1-JAN-2000 00:00)
|
||||
Duration float
|
||||
|
||||
Time datetime UTC time stamp
|
||||
TimeUnix float (UTC sec past 1-JAN-1970 00:00)
|
||||
Start datetime UTC time stamp
|
||||
StartUnix float (UTC sec past 1-JAN-1970 00:00)
|
||||
|
||||
Optional:
|
||||
RateLabel str
|
||||
TierLabel str
|
||||
|
||||
Sample:
|
||||
|
||||
<PriceCluster>
|
||||
<DeviceMacId>0xd8d5b9000000103f</DeviceMacId>
|
||||
<MeterMacId>0x000781000086d0fe</MeterMacId>
|
||||
<TimeStamp>0xffffffff</TimeStamp>
|
||||
<Price>0x0000000e</Price>
|
||||
<Currency>0x0348</Currency>
|
||||
<TrailingDigits>0x02</TrailingDigits>
|
||||
<Tier>0x01</Tier>
|
||||
<StartTime>0xffffffff</StartTime>
|
||||
<Duration>0xffff</Duration>
|
||||
<RateLabel>Tier 1</RateLabel>
|
||||
</PriceCluster>
|
||||
"""
|
||||
|
||||
# Hex keys turn into floats or ints. Taken care of automatically
|
||||
# in Base.__init__().
|
||||
_intHexKeys = [ "DeviceMacId", "MeterMacId", "Currency", "TrailingDigits",
|
||||
"Tier" ]
|
||||
_numHexKeys = [ "TimeStamp", "StartTime", "Price", "Duration" ]
|
||||
|
||||
_jsonKeys = [ "DeviceMacid", "MeterMacId", "Time", "Price", "Tier" ]
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
def __init__( self, node ):
|
||||
assert( node.tag == "PriceCluster" )
|
||||
Base.__init__( self, "PriceCluster", node )
|
||||
|
||||
if self.Price == 0xffffffff:
|
||||
self.Price = 0.0
|
||||
|
||||
self.Price = self.Price / 10**self.TrailingDigits
|
||||
|
||||
convert.time( self, "Time", "TimeUnix", self.TimeStamp )
|
||||
convert.time( self, "Start", "StartUnix", self.StartTime )
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
|
||||
#==========================================================================
|
||||
|
||||
|
||||
52
src/python/tHome/eagle/messages/Reading.py
Normal file
52
src/python/tHome/eagle/messages/Reading.py
Normal file
@@ -0,0 +1,52 @@
|
||||
#===========================================================================
|
||||
#
|
||||
# Reading Message
|
||||
#
|
||||
#===========================================================================
|
||||
from .Base import Base
|
||||
from . import convert
|
||||
|
||||
#==========================================================================
|
||||
class Reading ( Base ):
|
||||
"""Reading message
|
||||
|
||||
After construction, will have the following attributes:
|
||||
|
||||
Value float
|
||||
TimeStamp float (UTC sec past 1-JAN-2000 00:00)
|
||||
Type str
|
||||
|
||||
Time datetime UTC time stamp
|
||||
TimeUnix float (UTC sec past 1-JAN-1970 00:00)
|
||||
|
||||
Sample:
|
||||
|
||||
<Reading>
|
||||
<Value>-123.345</Value>
|
||||
<TimeStamp>0x1c531d48</TimeStamp>
|
||||
<Type>Summation</Type>
|
||||
</Reading>
|
||||
"""
|
||||
|
||||
# Hex keys turn into floats or ints. Taken care of automatically
|
||||
# in Base.__init__().
|
||||
_intHexKeys = []
|
||||
_numHexKeys = [ "TimeStamp" ]
|
||||
|
||||
_jsonKeys = [ "Value", "Type" ]
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
def __init__( self, node ):
|
||||
"""node == xml ETree node
|
||||
"""
|
||||
assert( node.tag == "Reading" )
|
||||
Base.__init__( self, "Reading", node )
|
||||
|
||||
convert.time( self, "Time", "TimeUnix", self.TimeStamp )
|
||||
self.Value = float( self.Value )
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
|
||||
#==========================================================================
|
||||
|
||||
|
||||
52
src/python/tHome/eagle/messages/ScheduleInfo.py
Normal file
52
src/python/tHome/eagle/messages/ScheduleInfo.py
Normal file
@@ -0,0 +1,52 @@
|
||||
#===========================================================================
|
||||
#
|
||||
# ScheduleInfo Message
|
||||
#
|
||||
#===========================================================================
|
||||
from .Base import Base
|
||||
|
||||
#==========================================================================
|
||||
class ScheduleInfo ( Base ):
|
||||
"""Schedule info message
|
||||
|
||||
After construction, will have the following attributes:
|
||||
|
||||
DeviceMacId int
|
||||
MeterMacId int
|
||||
Mode str
|
||||
Event str
|
||||
Frequency float (sec)
|
||||
Enabled str
|
||||
|
||||
Sample:
|
||||
|
||||
<ScheduleInfo>
|
||||
<DeviceMacId>0xd8d5b9000000103f</DeviceMacId>
|
||||
<MeterMacId>0x000781000086d0fe</MeterMacId>
|
||||
<Mode>default</Mode>
|
||||
<Event>message</Event>
|
||||
<Frequency>0x00000078</Frequency>
|
||||
<Enabled>Y</Enabled>
|
||||
</ScheduleInfo>
|
||||
"""
|
||||
|
||||
# Hex keys turn into floats or ints. Taken care of automatically
|
||||
# in Base.__init__().
|
||||
_numHexKeys = [ "Frequency" ]
|
||||
_intHexKeys = [ "DeviceMacId", "MeterMacId" ]
|
||||
|
||||
_jsonKeys = [ "DeviceMacid", "MeterMacId", "Mode", "Event", "Frequency",
|
||||
"Enabled" ]
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
def __init__( self, node ):
|
||||
"""node == xml ETree node
|
||||
"""
|
||||
assert( node.tag == "ScheduleInfo" )
|
||||
Base.__init__( self, "ScheduleInfo", node )
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
|
||||
#==========================================================================
|
||||
|
||||
|
||||
54
src/python/tHome/eagle/messages/TimeCluster.py
Normal file
54
src/python/tHome/eagle/messages/TimeCluster.py
Normal file
@@ -0,0 +1,54 @@
|
||||
#===========================================================================
|
||||
#
|
||||
# TimeCluster Message
|
||||
#
|
||||
#===========================================================================
|
||||
from .Base import Base
|
||||
from . import convert
|
||||
|
||||
#==========================================================================
|
||||
class TimeCluster ( Base ):
|
||||
"""Time cluster message
|
||||
|
||||
After construction, will have the following attributes:
|
||||
|
||||
DeviceMacId int
|
||||
MeterMacId int
|
||||
UTCTime float (UTC sec past 1-JAN-2000 00:00)
|
||||
LocalTime float (Local sec past 1-JAN-2000 00:00)
|
||||
|
||||
Time datetime UTC time stamp
|
||||
TimeUnix float (UTC sec past 1-JAN-1970 00:00)
|
||||
Local datetime local time stamp
|
||||
LocalUnix float (local sec past 1-JAN-1970 00:00)
|
||||
|
||||
Sample:
|
||||
|
||||
<TimeCluster>
|
||||
<DeviceMacId>0xd8d5b9000000103f</DeviceMacId>
|
||||
<MeterMacId>0x000781000086d0fe</MeterMacId>
|
||||
<UTCTime>0x1c531da7</UTCTime>
|
||||
<LocalTime>0x1c52ad27</LocalTime>
|
||||
</TimeCluster>
|
||||
"""
|
||||
|
||||
# Hex keys turn into floats or ints. Taken care of automatically
|
||||
# in Base.__init__().
|
||||
_intHexKeys = [ "DeviceMacId", "MeterMacId" ]
|
||||
_numHexKeys = [ "UTCTime", "LocalTime" ]
|
||||
|
||||
_jsonKeys = [ "DeviceMacid", "MeterMacId", "LocalUnix" ]
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
def __init__( self, node ):
|
||||
assert( node.tag == "TimeCluster" )
|
||||
Base.__init__( self, "TimeCluster", node )
|
||||
|
||||
convert.time( self, "Time", "TimeUnix", self.UTCTime )
|
||||
convert.time( self, "Local", "LocalUnix", self.LocalTime )
|
||||
|
||||
#------------------------------------------------------------------------
|
||||
|
||||
#==========================================================================
|
||||
|
||||
|
||||
49
src/python/tHome/eagle/messages/__init__.py
Normal file
49
src/python/tHome/eagle/messages/__init__.py
Normal file
@@ -0,0 +1,49 @@
|
||||
#===========================================================================
|
||||
#
|
||||
# RainForest Eagle XML messages
|
||||
#
|
||||
#===========================================================================
|
||||
|
||||
__doc__ = """Decodes Eagle XML messages.
|
||||
|
||||
One class per message type. Use the eagle.parse() function to do the
|
||||
conversions.
|
||||
"""
|
||||
|
||||
#===========================================================================
|
||||
|
||||
from . import convert
|
||||
from .Base import Base
|
||||
from .BlockPriceDetail import BlockPriceDetail
|
||||
from .CurrentSummation import CurrentSummation
|
||||
from .DeviceInfo import DeviceInfo
|
||||
from .FastPollStatus import FastPollStatus
|
||||
from .InstantaneousDemand import InstantaneousDemand
|
||||
from .MessageCluster import MessageCluster
|
||||
from .MeterInfo import MeterInfo
|
||||
from .NetworkInfo import NetworkInfo
|
||||
from .PriceCluster import PriceCluster
|
||||
from .Reading import Reading
|
||||
from .ScheduleInfo import ScheduleInfo
|
||||
from .TimeCluster import TimeCluster
|
||||
|
||||
#===========================================================================
|
||||
|
||||
# Map XML names to class names.
|
||||
tagMap = {
|
||||
"BlockPriceDetail" : BlockPriceDetail,
|
||||
"CurrentSummation" : CurrentSummation, # socket API
|
||||
"CurrentSummationDelivered" : CurrentSummation, # cloud API
|
||||
"DeviceInfo" : DeviceInfo,
|
||||
"FastPollStatus" : FastPollStatus,
|
||||
"InstantaneousDemand" : InstantaneousDemand,
|
||||
"MessageCluster" : MessageCluster,
|
||||
"MeterInfo" : MeterInfo,
|
||||
"NetworkInfo" : NetworkInfo,
|
||||
"PriceCluster" : PriceCluster,
|
||||
"Reading" : Reading,
|
||||
"ScheduleInfo" : ScheduleInfo,
|
||||
"TimeCluster" : TimeCluster,
|
||||
}
|
||||
|
||||
#===========================================================================
|
||||
80
src/python/tHome/eagle/messages/convert.py
Normal file
80
src/python/tHome/eagle/messages/convert.py
Normal file
@@ -0,0 +1,80 @@
|
||||
#===========================================================================
|
||||
#
|
||||
# Field conversion utilities.
|
||||
#
|
||||
#===========================================================================
|
||||
import datetime
|
||||
|
||||
#==========================================================================
|
||||
|
||||
# Eagle reference date as a datetime object.
|
||||
eagleT0 = datetime.datetime( 2000, 1, 1 )
|
||||
|
||||
# Delta in seconds between Eagle ref and UNIX ref time.
|
||||
eagleT0_unixT0 = ( eagleT0 - datetime.datetime( 1970, 1, 1 ) ).total_seconds()
|
||||
|
||||
#==========================================================================
|
||||
def hexKeys( obj, keyList, cvtFunc ):
|
||||
for key in keyList:
|
||||
strVal = getattr( obj, key, None )
|
||||
if strVal is None:
|
||||
continue
|
||||
|
||||
intVal = int( strVal, 16 )
|
||||
setattr( obj, key, cvtFunc( intVal ) )
|
||||
|
||||
#==========================================================================
|
||||
def time( obj, timeKey, unixKey, eagleSec ):
|
||||
timeValue = None
|
||||
unixValue = None
|
||||
if eagleSec:
|
||||
timeValue = toDateTime( eagleSec )
|
||||
unixValue = toUnixTime( eagleSec )
|
||||
|
||||
setattr( obj, timeKey, timeValue )
|
||||
setattr( obj, unixKey, unixValue )
|
||||
|
||||
|
||||
#==========================================================================
|
||||
def zeroToOne( obj, keyList ):
|
||||
for key in keyList:
|
||||
val = getattr( obj, key )
|
||||
if not val:
|
||||
setattr( obj, key, 1.0 )
|
||||
|
||||
#==========================================================================
|
||||
def toValue( value, multiplier, divisor ):
|
||||
return float( value ) * multiplier / divisor
|
||||
|
||||
#==========================================================================
|
||||
def toSigned4( value ):
|
||||
if value > 0x7FFFFFFF:
|
||||
return value - 0xFFFFFFFF
|
||||
return value
|
||||
|
||||
|
||||
#==========================================================================
|
||||
def toUnixTime( eagleSec ):
|
||||
"""Input is EAGLE UTC seconds past 00:00:00 1-jan-2000
|
||||
|
||||
Returns a float of UTC seconds past UTC 1-jan-1970.
|
||||
"""
|
||||
return eagleSec + eagleT0_unixT0
|
||||
|
||||
#==========================================================================
|
||||
def toDateTime( eagleSec ):
|
||||
"""Input is EAGLE UTC seconds past 00:00:00 1-jan-2000
|
||||
|
||||
Returns a datetime object
|
||||
"""
|
||||
return eagleT0 + datetime.timedelta( 0, float( eagleSec ) )
|
||||
|
||||
#==========================================================================
|
||||
def fromTime( dateTime ):
|
||||
"datetime object MUST be utc"
|
||||
dt = dateTime - eagleT0
|
||||
isec = int( dt.total_seconds() )
|
||||
return hex( isec )
|
||||
|
||||
#==========================================================================
|
||||
|
||||
29
src/python/tHome/eagle/messages/test/BlockPriceDetail.py
Normal file
29
src/python/tHome/eagle/messages/test/BlockPriceDetail.py
Normal file
@@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import xml.etree.ElementTree as ET
|
||||
import tHome.eagle as E
|
||||
|
||||
s="""
|
||||
<BlockPriceDetail>
|
||||
<DeviceMacId>0xd8d5b9000000103f</DeviceMacId>
|
||||
<MeterMacId>0x000781000086d0fe</MeterMacId>
|
||||
<TimeStamp>0x1c531d6b</TimeStamp>
|
||||
<CurrentStart>0x00000000</CurrentStart>
|
||||
<CurrentDuration>0x0000</CurrentDuration>
|
||||
<BlockPeriodConsumption>0x0000000000231c38</BlockPeriodConsumption>
|
||||
<BlockPeriodConsumptionMultiplier>0x00000001</BlockPeriodConsumptionMultiplier>
|
||||
<BlockPeriodConsumptionDivisor>0x000003e8</BlockPeriodConsumptionDivisor>
|
||||
<NumberOfBlocks>0x00</NumberOfBlocks>
|
||||
<Multiplier>0x00000001</Multiplier>
|
||||
<Divisor>0x00000001</Divisor>
|
||||
<Currency>0x0348</Currency>
|
||||
<TrailingDigits>0x00</TrailingDigits>
|
||||
</BlockPriceDetail>
|
||||
"""
|
||||
|
||||
root = ET.fromstring( s )
|
||||
|
||||
n = E.messages.BlockPriceDetail( root )
|
||||
print n
|
||||
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import xml.etree.ElementTree as ET
|
||||
import tHome.eagle as E
|
||||
|
||||
s="""
|
||||
<CurrentSummationDelivered>
|
||||
<DeviceMacId>0xd8d5b9000000103f</DeviceMacId>
|
||||
<MeterMacId>0x000781000086d0fe</MeterMacId>
|
||||
<TimeStamp>0x1c531e54</TimeStamp>
|
||||
<SummationDelivered>0x0000000001321a5f</SummationDelivered>
|
||||
<SummationReceived>0x00000000003f8240</SummationReceived>
|
||||
<Multiplier>0x00000001</Multiplier>
|
||||
<Divisor>0x000003e8</Divisor>
|
||||
<DigitsRight>0x01</DigitsRight>
|
||||
<DigitsLeft>0x06</DigitsLeft>
|
||||
<SuppressLeadingZero>Y</SuppressLeadingZero>
|
||||
</CurrentSummationDelivered>
|
||||
"""
|
||||
|
||||
root = ET.fromstring( s )
|
||||
|
||||
n = E.messages.CurrentSummation( root )
|
||||
print n
|
||||
|
||||
|
||||
26
src/python/tHome/eagle/messages/test/DeviceInfo.py
Normal file
26
src/python/tHome/eagle/messages/test/DeviceInfo.py
Normal file
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import xml.etree.ElementTree as ET
|
||||
import tHome.eagle as E
|
||||
|
||||
s="""
|
||||
<DeviceInfo>
|
||||
<DeviceMacId>0xd8d5b9000000103f</DeviceMacId>
|
||||
<InstallCode>0x8ba7f1dee6c4f5cc</InstallCode>
|
||||
<LinkKey>0x2b26f9124113b1e2b317d402ed789a47</LinkKey>
|
||||
<FWVersion>1.4.47 (6798)</FWVersion>
|
||||
<HWVersion>1.2.3</HWVersion>
|
||||
<ImageType>0x1301</ImageType>
|
||||
<Manufacturer>Rainforest Automation, Inc.</Manufacturer>
|
||||
<ModelId>Z109-EAGLE</ModelId>
|
||||
<DateCode>2013103023220630</DateCode>
|
||||
<Port>/dev/ttySP0</Port>
|
||||
</DeviceInfo>
|
||||
"""
|
||||
|
||||
root = ET.fromstring( s )
|
||||
|
||||
n = E.messages.DeviceInfo( root )
|
||||
print n
|
||||
|
||||
|
||||
20
src/python/tHome/eagle/messages/test/FastPollStatus.py
Normal file
20
src/python/tHome/eagle/messages/test/FastPollStatus.py
Normal file
@@ -0,0 +1,20 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import xml.etree.ElementTree as ET
|
||||
import tHome.eagle as E
|
||||
|
||||
s="""
|
||||
<FastPollStatus>
|
||||
<DeviceMacId>0xd8d5b9000000103f</DeviceMacId>
|
||||
<MeterMacId>0x000781000086d0fe</MeterMacId>
|
||||
<Frequency>0x00</Frequency>
|
||||
<EndTime>0xFFFFFFFF</EndTime>
|
||||
</FastPollStatus>
|
||||
"""
|
||||
|
||||
root = ET.fromstring( s )
|
||||
|
||||
n = E.messages.FastPollStatus( root )
|
||||
print n
|
||||
|
||||
|
||||
25
src/python/tHome/eagle/messages/test/InstantaneousDemand.py
Normal file
25
src/python/tHome/eagle/messages/test/InstantaneousDemand.py
Normal file
@@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import xml.etree.ElementTree as ET
|
||||
import tHome.eagle as E
|
||||
|
||||
s="""
|
||||
<InstantaneousDemand>
|
||||
<DeviceMacId>0xd8d5b9000000103f</DeviceMacId>
|
||||
<MeterMacId>0x000781000086d0fe</MeterMacId>
|
||||
<TimeStamp>0x1c531d48</TimeStamp>
|
||||
<Demand>0x00032d</Demand>
|
||||
<Multiplier>0x00000001</Multiplier>
|
||||
<Divisor>0x000003e8</Divisor>
|
||||
<DigitsRight>0x03</DigitsRight>
|
||||
<DigitsLeft>0x06</DigitsLeft>
|
||||
<SuppressLeadingZero>Y</SuppressLeadingZero>
|
||||
</InstantaneousDemand>
|
||||
"""
|
||||
|
||||
root = ET.fromstring( s )
|
||||
|
||||
n = E.messages.InstantaneousDemand( root )
|
||||
print n
|
||||
|
||||
|
||||
27
src/python/tHome/eagle/messages/test/MessageCluster.py
Normal file
27
src/python/tHome/eagle/messages/test/MessageCluster.py
Normal file
@@ -0,0 +1,27 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import xml.etree.ElementTree as ET
|
||||
import tHome.eagle as E
|
||||
|
||||
s="""
|
||||
<MessageCluster>
|
||||
<DeviceMacId>0xd8d5b9000000103f</DeviceMacId>
|
||||
<MeterMacId>0x000781000086d0fe</MeterMacId>
|
||||
<TimeStamp></TimeStamp>
|
||||
<Id></Id>
|
||||
<Text></Text>
|
||||
<Priority></Priority>
|
||||
<StartTime></StartTime>
|
||||
<Duration></Duration>
|
||||
<ConfirmationRequired>N</ConfirmationRequired>
|
||||
<Confirmed>N</Confirmed>
|
||||
<Queue>Active</Queue>
|
||||
</MessageCluster>
|
||||
"""
|
||||
|
||||
root = ET.fromstring( s )
|
||||
|
||||
n = E.messages.MessageCluster( root )
|
||||
print n
|
||||
|
||||
|
||||
24
src/python/tHome/eagle/messages/test/MeterInfo.py
Normal file
24
src/python/tHome/eagle/messages/test/MeterInfo.py
Normal file
@@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import xml.etree.ElementTree as ET
|
||||
import tHome.eagle as E
|
||||
|
||||
s="""
|
||||
<MeterInfo>
|
||||
<DeviceMacId>0xd8d5b9000000103f</DeviceMacId>
|
||||
<MeterMacId>0x000781000086d0fe</MeterMacId>
|
||||
<Type>0x0000</Type>
|
||||
<Nickname></Nickname>
|
||||
<Account></Account>
|
||||
<Auth></Auth>
|
||||
<Host></Host>
|
||||
<Enabled>Y</Enabled>
|
||||
</MeterInfo>
|
||||
"""
|
||||
|
||||
root = ET.fromstring( s )
|
||||
|
||||
n = E.messages.MeterInfo( root )
|
||||
print n
|
||||
|
||||
|
||||
24
src/python/tHome/eagle/messages/test/NetworkInfo.py
Normal file
24
src/python/tHome/eagle/messages/test/NetworkInfo.py
Normal file
@@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import xml.etree.ElementTree as ET
|
||||
import tHome.eagle as E
|
||||
|
||||
s="""
|
||||
<NetworkInfo>
|
||||
<DeviceMacId>0xd8d5b9000000103f</DeviceMacId>
|
||||
<CoordMacId>0x000781000086d0fe</CoordMacId>
|
||||
<Status>Connected</Status>
|
||||
<Description>Successfully Joined</Description>
|
||||
<ExtPanId>0x000781000086d0fe</ExtPanId>
|
||||
<Channel>20</Channel>
|
||||
<ShortAddr>0xe1aa</ShortAddr>
|
||||
<LinkStrength>0x64</LinkStrength>
|
||||
</NetworkInfo>
|
||||
"""
|
||||
|
||||
root = ET.fromstring( s )
|
||||
|
||||
n = E.messages.NetworkInfo( root )
|
||||
print n
|
||||
|
||||
|
||||
26
src/python/tHome/eagle/messages/test/PriceCluster.py
Normal file
26
src/python/tHome/eagle/messages/test/PriceCluster.py
Normal file
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import xml.etree.ElementTree as ET
|
||||
import tHome.eagle as E
|
||||
|
||||
s="""
|
||||
<PriceCluster>
|
||||
<DeviceMacId>0xd8d5b9000000103f</DeviceMacId>
|
||||
<MeterMacId>0x000781000086d0fe</MeterMacId>
|
||||
<TimeStamp>0xffffffff</TimeStamp>
|
||||
<Price>0x0000000e</Price>
|
||||
<Currency>0x0348</Currency>
|
||||
<TrailingDigits>0x02</TrailingDigits>
|
||||
<Tier>0x01</Tier>
|
||||
<StartTime>0xffffffff</StartTime>
|
||||
<Duration>0xffff</Duration>
|
||||
<RateLabel>Tier 1</RateLabel>
|
||||
</PriceCluster>
|
||||
"""
|
||||
|
||||
root = ET.fromstring( s )
|
||||
|
||||
n = E.messages.PriceCluster( root )
|
||||
print n
|
||||
|
||||
|
||||
19
src/python/tHome/eagle/messages/test/Reading.py
Normal file
19
src/python/tHome/eagle/messages/test/Reading.py
Normal file
@@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import xml.etree.ElementTree as ET
|
||||
import tHome.eagle as E
|
||||
|
||||
s="""
|
||||
<Reading>
|
||||
<Value>-123.345</Value>
|
||||
<TimeStamp>0x1c531d48</TimeStamp>
|
||||
<Type>Summation</Type>
|
||||
</Reading>
|
||||
"""
|
||||
|
||||
root = ET.fromstring( s )
|
||||
|
||||
n = E.messages.Reading( root )
|
||||
print n
|
||||
|
||||
|
||||
22
src/python/tHome/eagle/messages/test/ScheduleInfo.py
Normal file
22
src/python/tHome/eagle/messages/test/ScheduleInfo.py
Normal file
@@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import xml.etree.ElementTree as ET
|
||||
import tHome.eagle as E
|
||||
|
||||
s="""
|
||||
<ScheduleInfo>
|
||||
<DeviceMacId>0xd8d5b9000000103f</DeviceMacId>
|
||||
<MeterMacId>0x000781000086d0fe</MeterMacId>
|
||||
<Mode>default</Mode>
|
||||
<Event>message</Event>
|
||||
<Frequency>0x00000078</Frequency>
|
||||
<Enabled>Y</Enabled>
|
||||
</ScheduleInfo>
|
||||
"""
|
||||
|
||||
root = ET.fromstring( s )
|
||||
|
||||
n = E.messages.ScheduleInfo( root )
|
||||
print n
|
||||
|
||||
|
||||
20
src/python/tHome/eagle/messages/test/TimeCluster.py
Normal file
20
src/python/tHome/eagle/messages/test/TimeCluster.py
Normal file
@@ -0,0 +1,20 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import xml.etree.ElementTree as ET
|
||||
import tHome.eagle as E
|
||||
|
||||
s="""
|
||||
<TimeCluster>
|
||||
<DeviceMacId>0xd8d5b9000000103f</DeviceMacId>
|
||||
<MeterMacId>0x000781000086d0fe</MeterMacId>
|
||||
<UTCTime>0x1c531da7</UTCTime>
|
||||
<LocalTime>0x1c52ad27</LocalTime>
|
||||
</TimeCluster>
|
||||
"""
|
||||
|
||||
root = ET.fromstring( s )
|
||||
|
||||
n = E.messages.TimeCluster( root )
|
||||
print n
|
||||
|
||||
|
||||
26
src/python/tHome/eagle/parse.py
Normal file
26
src/python/tHome/eagle/parse.py
Normal file
@@ -0,0 +1,26 @@
|
||||
#===========================================================================
|
||||
#
|
||||
# Parse XML messages into an object.
|
||||
#
|
||||
#===========================================================================
|
||||
import xml.etree.ElementTree as ET
|
||||
from . import messages
|
||||
|
||||
#==========================================================================
|
||||
|
||||
# <rainForest ...>
|
||||
# <[Message]>...</[Message]>
|
||||
# </rainForest>
|
||||
def parse( xmlText ):
|
||||
root = ET.fromstring( xmlText )
|
||||
assert( root.tag == "rainforest" )
|
||||
|
||||
child = root[0]
|
||||
|
||||
msgClass = messages.tagMap.get( child.tag, None )
|
||||
if not msgClass:
|
||||
return None
|
||||
|
||||
return msgClass( child )
|
||||
|
||||
#==========================================================================
|
||||
Reference in New Issue
Block a user