Browse Source

works ( kinda )

main
Peter Shipley 11 years ago
parent
commit
5a1f31743c
4 changed files with 214 additions and 124 deletions
  1. +8
    -1
      README.md
  2. +149
    -118
      RainEagle/EagleClass.py
  3. +11
    -3
      RainEagle/__init__.py
  4. +46
    -2
      test.py

+ 8
- 1
README.md View File

@@ -2,7 +2,14 @@
Python Class for utilizing the Rainforest Automation Eagle ( RFA-Z109 ) socket API


*** This is just skeleton so far ***
import import RainEagle

raineagle = RainEagle.Eagle( debug=0 , addr="10.1.1.39")
ret_data = eg.list_devices()

print "device MacID = ", ret_data['DeviceInfo']['DeviceMacId']




Rainforest Automation Documentation


+ 149
- 118
RainEagle/EagleClass.py View File

@@ -5,10 +5,15 @@ import os
import time
import xml.etree.ElementTree as ET

from pprint import pprint


__all__ = ['Eagle']

def et2d(et) :

""" Etree to Dict

converts an ETree to a Dict Tree
@@ -55,7 +60,17 @@ def et2d(et) :
#
# Simple Base class for ISY Class
class Eagle(object) :
"""
Class for talking to Rainforest Automation EAGLE (RFA-Z109)

args:
debug print debug messages if true
addr address of device
port port on device (default 5002)
getmac connect to device at start up and get macid (default true)

Currently there is very little error handling ( if any at all )
"""
def __init__(self, **kwargs):
self.debug = kwargs.get("debug", 0)

@@ -63,143 +78,71 @@ class Eagle(object) :
print self.__class__.__name__, __name__
self.addr = kwargs.get("addr", os.getenv('EAGLE_ADDR', None))
self.port = kwargs.get("port", os.getenv('EAGLE_PORT', 5002))
self.getmac = kwargs.get("getmac", True)
self.soc = None
self.macid = None

# preload
if self.getmac :
self.device_info = self.list_devices()
if self.debug :
pprint(self.device_info)
# self.macid = self.device_info['DeviceInfo']['DeviceMacId']
if self.debug :
print "DeviceMacId = ", self.macid

def connect(self) :
self.soc = socket.create_connection( (self.addr, self.port), 10)

# self.soc_rf = self.soc.makefile("rb")
# self.soc_wf = self.soc.makefile("wb")

def disconnect(self):

# try :
# if self.soc_rf :
# self.soc_rf.close()
# self.soc_rf = False
# except IOError :
# pass
#
# try :
# if self.soc_wf :
# self.soc_wf.close()
# self.soc_wf = False
# except IOError :
# pass
#
try :
if self.soc :
self.soc_sock.close()
self.soc_sock = False
except IOError :
pass

def _reconnect(self):
self.disconnect()
self.connect()


def _send_comm(self, cmd, **kwargs):

commstr = "<LocalCommand>\r\n "
commstr += "<Name>{0!s}</Name>\r\n".format(cmd)
for k, v in kwargs.items() :
commstr += "<{0}>{1!s}</{0}>\r\n".format(k, v)
commstr += "</LocalCommand>\r\n"

#+ self.soc.send(commstr)
print "commstr : ", commstr

# self.soc_wf.write(commstr)
# self.soc_wf.flush()

#+ time.sleep(1)

replystr = ""
#+ while 1 :
#+ buf = self.soc.recv(1000)
#+ if not buf:
#+ break
#+ replystr += buf

return replystr

# commands as class funtions

def list_devices(self):
comm_responce = self._send_comm("list_devices")
# temp debug data
comm_responce = "<DeviceInfo>" \
" <DeviceMacId>0xd8d5b90000000xxx</DeviceMacId>" \
" <InstallCode>0x9ac4382dffa81xxx</InstallCode>" \
" <LinkKeyHigh>7e572b66c5b444xxx</LinkKeyHigh>" \
" <LinkKeyLow>94227dca4e773xxx</LinkKeyLow>" \
" <FWVersion>1.4.27 (5278)</FWVersion>" \
" <HWVersion>1.2.3</HWVersion>" \
" <Manufacturer>Rainforest Automation, I</Manufacturer>" \
" <ModelId>RFA-Z109 EAGLE</ModelId>" \
" <DateCode>20130308PO020621</DateCode>" \
"</DeviceInfo>\n"

if self.debug :
print "comm_responce =", comm_responce
etree = ET.fromstring('<S>' + comm_responce + '</S>' )
rv = et2d(etree)
if self.macid == None :
self.macid = rv['DeviceInfo']['DeviceMacId']
return rv

# 3
def get_device_data(self, macid) :
def get_device_data(self, macid=None) :
""" Send the GET_DEVICE_DATA command to get a data dump """
if macid == None :
macid = self.macid
comm_responce = self._send_comm("get_device_data", MacId=macid)
# temp debug data
comm_responce = "<NetworkInfo>" \
" <DeviceMacId>0xd8d5b90000000xxx</DeviceMacId>" \
" <Status>Rejoining</Status>" \
" <MeterMacId>0x001350030011bxxx</MeterMacId>" \
" <ExtPanId>0x7fffffffffffffff</ExtPanId>" \
" <ShortAddr>0x0000ffff</ShortAddr>" \
" <Channel>24</Channel>" \
" <LinkStrength>156</LinkStrength>" \
"</NetworkInfo>" \
"<DeviceInfo>" \
" <DeviceMacId>0xd8d5b90000000xxx</DeviceMacId>" \
" <InstallCode>0x9ac4382dffa81xxx</InstallCode>" \
" <LinkKeyHigh>7e572b66c5b44xxx</LinkKeyHigh>" \
" <LinkKeyLow>94227dca4e773xxx</LinkKeyLow>" \
" <FWVersion>1.4.27 (5278)</FWVersion>" \
" <HWVersion>1.2.3</HWVersion>" \
" <Manufacturer>Rainforest Automation, I</Manufacturer>" \
" <ModelId>RFA-Z109 EAGLE</ModelId>" \
" <DateCode>20130308PO020621</DateCode>" \
"</DeviceInfo>" \
"<InstantaneousDemand>" \
" <DeviceMacId>0xd8d5b90000000xxx</DeviceMacId>" \
" <MeterMacId>0x001350030011bxxx</MeterMacId>" \
" <Demand>0x00000bf1</Demand>" \
" <TimeStamp>0x195193e3</TimeStamp>" \
" <Multiplier>0x00000001</Multiplier>" \
" <Divisor>0x000003e8</Divisor>" \
" <DigitsRight>0x00000003</DigitsRight>" \
" <DigitsLeft>0x0000000f</DigitsLeft>" \
" <SuppressLeadingZero>0x0001</SuppressLeadingZero>" \
"</InstantaneousDemand>"

etree = ET.fromstring('<S>' + comm_responce + '</S>' )
rv = et2d(etree)
return rv

# 10
def get_instantaneous_demand(self, macid, interval) :
""" Send the GET_INSTANTANEOUS_DEMAND command to get the real time demand from the meter"""
def get_instantaneous_demand(self, macid=None) :
""" Send the GET_INSTANTANEOUS_DEMAND command
get the real time demand from the meter

args:
MacId 16 hex digits, MAC addr of EAGLE ZigBee radio
"""
if macid == None :
macid = self.macid
comm_responce = self._send_comm("get_instantaneous_demand",
MacId=macid, Interval=interval)
MacId=macid)
etree = ET.fromstring('<S>' + comm_responce + '</S>' )
rv = et2d(etree)
return rv

# 11
def get_demand_values(self, macid, interval, frequency=None ) :
""" Send the GET_DEMAND_VALUES command to get a series of instantaneous demand values"""
def get_demand_values(self, macid=None, interval="hour", frequency=None ) :
""" Send the GET_DEMAND_VALUES command
get a series of instantaneous demand values

args:
MacId 16 hex digits, MAC addr of EAGLE ZigBee radio
Interval hour | day | week
[Frequency] int seconds between samples
"""
if macid == None :
macid = self.macid
kwargs = {"MacId": macid, "Interval": interval}
if frequency :
kwargs["Frequency"] = frequency
@@ -209,8 +152,16 @@ class Eagle(object) :
return rv

# 12
def get_summation_values(self, macid, interval) :
""" Send the GET_SUMMATION_VALUES command to get a series of net summation values """
def get_summation_values(self, macid=None, interval="day") :
""" Send the GET_SUMMATION_VALUES command
get a series of net summation values

args:
MacId 16 hex digits, MAC addr of EAGLE ZigBee radio
Interval day | week | month | year
"""
if macid == None :
macid = self.macid
comm_responce = self._send_comm("get_summation_values",
MacId=macid, Interval=interval )
etree = ET.fromstring('<S>' + comm_responce + '</S>' )
@@ -218,8 +169,22 @@ class Eagle(object) :
return rv

# 14
def set_fast_poll(self, macid, frequency, duration) :
""" set the fast poll mode on the meter. """
def set_fast_poll(self, macid=None, frequency="0x04", duration="0xFF") :
""" Send the SET_FAST_POLL command
set the fast poll mode on the meter

args:
MacId 16 hex digits, MAC addr of EAGLE ZigBee radio
Frequency 0x01 - 0xFF Freq to poll meter, in seconds
Duration 0x00 - 0x0F Duration of fast poll mode, in minutes (max 15)
"""
if macid == None :
macid = self.macid
if isinstance(frequency, int) :
frequency = "{:#04x}".format(m)
if isinstance(duration, int) :
frequency = "{:#04x}".format(m)

comm_responce = self._send_comm("get_instantaneous_demand",
MacId=macid, Frequency=frequency, Duration=duration)
etree = ET.fromstring('<S>' + comm_responce + '</S>' )
@@ -227,8 +192,15 @@ class Eagle(object) :
return rv

# 15
def get_fast_poll_status(self, macid) :
""" get the current status of fast poll mode. """
def get_fast_poll_status(self, macid=None) :
""" Send the GET_FAST_POLL_STATUS command
get the current status of fast poll mode.

args:
MacId 16 hex digits, MAC addr of EAGLE ZigBee radio
"""
if macid == None :
macid = self.macid
comm_responce = self._send_comm("get_fast_poll_status", MacId=macid)
etree = ET.fromstring('<S>' + comm_responce + '</S>' )
rv = et2d(etree)
@@ -236,8 +208,12 @@ class Eagle(object) :


# 17
def get_history_data(self, macid, starttime, endtime=None, frequency=None ) :
""" get a series of summation values over an interval of time """
def get_history_data(self, macid=None, starttime="0x00000000", endtime=None, frequency=None ) :
""" Send the GET_HISTORY_DATA command
get a series of summation values over an interval of time
"""
if macid == None :
macid = self.macid
kwargs = {"MacId": macid, "StartTime": starttime}
if endtime :
kwargs["EndTime"] = endtime
@@ -248,6 +224,61 @@ class Eagle(object) :
rv = et2d(etree)
return rv


# Support functions

def connect(self) :
self.soc = socket.create_connection( (self.addr, self.port), 10)

def disconnect(self):
try :
if self.soc :
self.soc.close()
self.soc = False
except IOError :
pass


def _send_comm(self, cmd, **kwargs):

if cmd == "set_fast_poll" :
command_tag = "RavenCommand"
else :
command_tag = "LocalCommand"

commstr = "<{0}>\n ".format(command_tag)
commstr += "<Name>{0!s}</Name>\n".format(cmd)
for k, v in kwargs.items() :
commstr += "<{0}>{1!s}</{0}>\n".format(k, v)
commstr += "</{0}>\n".format(command_tag)

self.connect()
self.soc.sendall(commstr)
if self.debug :
print "commstr : \n", commstr

# time.sleep(1)

replystr = ""
while 1 :
buf = self.soc.recv(1000)
if not buf:
break
replystr += buf

self.disconnect()
return replystr

def to_unix_time(self, t) :
""" converts time stored as
offset in seconds from "Jan 1 00:00:00 2000"
to unix's epoch of 1970
"""
if isinstance(t, (int, long, float) ) :
return t + 946684800
if isinstance(t, str) and t.startswith('0x') :
return 946684800 + int(t, 16)

# Do nothing
# (syntax check)
#


+ 11
- 3
RainEagle/__init__.py View File

@@ -2,21 +2,29 @@

"""


import sys
if sys.hexversion < 0x20703f0 :
sys.stderr.write("You need python 2.7 or later to run this script\n")

__revision__ = "$Id: 20140301 $"
__version__ = '0.1.20140301'
__author__ = 'Peter Shipley <peter.shipley@gmail.com>'
__copyright__ = "Copyright (C) 2014 Peter Shipley"
__license__ = "BSD"


from RainEagle.EagleClass import Eagle
from EagleClass import Eagle
#from RainEagle.EagleClass import Eagle

__all__ = ['Eagle']



if __name__ == "__main__":
import __main__
#import __main__
#print(__main__.__file___)
print("ISY.__init__")
print("RainEagle.__init__")
print("syntax ok")
exit(0)



+ 46
- 2
test.py View File

@@ -1,12 +1,56 @@

import RainEagle
import time
from pprint import pprint

def too_unix_time(t) :
""" converts time stored as
offset in seconds from "Jan 1 00:00:00 2000"
to unix's epoch of 1970
"""
if isinstance(t, (int, long, float) ) :
return t + 946684800
if isinstance(t, str) and t.startswith('0x') :
return 946684800 + int(t, 16)

eg = RainEagle.Eagle( debug=1 )

eg = RainEagle.Eagle( debug=0 , addr="10.1.1.39")


print "\nlist_devices :"
r = eg.list_devices()
pprint(r)

r = eg.get_device_data("EE:24:01:05:50:23")
# print "\nget_device_data :"
# r = eg.get_device_data()
# pprint(r)
# time_stamp_str=r['InstantaneousDemand']['TimeStamp']
# time_stamp = eg.to_unix_time(time_stamp_str)
# print "time = ", time.asctime(time.localtime(time_stamp))


print "\nget_instantaneous_demand :"
r = eg.get_instantaneous_demand()
pprint(r)


print "\nget_demand_values :"
r = eg.get_demand_values(eg.macid, interval="hour")
pprint(r)

print "\nget_summation_values :"
r = eg.get_summation_values(eg.macid, interval="day")
pprint(r)

# set_fast_poll(self, macid=None, frequency, duration) :


print "\nget_fast_poll_status :"
r = eg.get_fast_poll_status(eg.macid)
pprint(r)

etime = eg.to_unix_time( r['FastPollStatus']['EndTime'])
print "EndTime = ", time.asctime(time.localtime(etime))

# def get_history_data(self, macid=None, starttime,
# endtime=None, frequency=None ) :

Loading…
Cancel
Save