diff --git a/RainEagle/EagleClass.py b/RainEagle/EagleClass.py index 984d25b..c723e09 100644 --- a/RainEagle/EagleClass.py +++ b/RainEagle/EagleClass.py @@ -1,5 +1,4 @@ - __author__ = 'Peter Shipley ' __copyright__ = "Copyright (C) 2014 Peter Shipley" __license__ = "BSD" @@ -20,12 +19,11 @@ from warnings import warn from pprint import pprint -api_arg_format = { - -} +# api_arg_format = { } __all__ = ['Eagle', 'RainEagleResponseError', 'to_epoch_1970, to_epoch_2000'] + class RainEagleResponseError(RuntimeError): """General exception for responce errors from Rainforest Automation EAGLE (RFA-Z109) @@ -33,13 +31,12 @@ class RainEagleResponseError(RuntimeError): pass - def to_epoch_2000(t) : """ converts time stored as to unix's epoch of 1970 offset in seconds from "Jan 1 00:00:00 2000" """ - if isinstance(t, time.struct_time ) : + if isinstance(t, time.struct_time) : t = time.mktime(t) return t - 946684800 @@ -49,7 +46,7 @@ def to_epoch_1970(t) : offset in seconds from "Jan 1 00:00:00 2000" to unix's epoch of 1970 """ - if isinstance(t, (int, long, float) ) : + if isinstance(t, (int, long, float)) : return t + 946684800 if isinstance(t, str) and t.startswith('0x') : return 946684800 + int(t, 16) @@ -61,7 +58,7 @@ def _et2d(et) : converts an ETree to a Dict Tree lists are created for duplicate tag - if there are multiple XML of the name name + if there are multiple XML of the same name an list array is used attrib tags are converted to "tag_name" + "attrib_name" @@ -98,7 +95,7 @@ def _et2d(et) : return d -def twos_comp(val, bits=32): +def _twos_comp(val, bits=32): """compute the 2's compliment of int value val""" if( (val&(1<<(bits-1))) != 0 ): val = val - (1< 2147483647) or ( i < -2147483648 ) : - warn("_tohex : signed int to large (" + str(n) + ")\n", RuntimeWarning, stacklevel=2) + if (i > 2147483647) or (i < -2147483648) : + warn("_tohex : signed int to large (" + str(n) + ")\n", + RuntimeWarning, stacklevel=2) if i < 0 : i += 0x100000000 @@ -140,6 +138,7 @@ class Eagle(object) : addr address of device port port on device (default 5002) getmac connect to device at start up and get macid (default true) + timeout TCP socket timeout Currently there is very little error handling ( if any at all ) """ @@ -182,7 +181,7 @@ class Eagle(object) : print "comm_responce =", comm_responce if comm_responce is None: raise RainEagleResponseError("list_devices : Null reply") - etree = ET.fromstring('' + comm_responce + '' ) + etree = ET.fromstring('' + comm_responce + '') rv = _et2d(etree) if self.macid is None : self.macid = rv['DeviceInfo']['DeviceMacId'] @@ -196,7 +195,7 @@ class Eagle(object) : comm_responce = self._send_soc_comm("get_device_data", MacId=macid) if comm_responce is None: raise RainEagleResponseError("get_device_data : Null reply") - etree = ET.fromstring('' + comm_responce + '' ) + etree = ET.fromstring('' + comm_responce + '') rv = _et2d(etree) return rv @@ -214,12 +213,12 @@ class Eagle(object) : MacId=macid) if comm_responce is None: raise RainEagleResponseError("get_instantaneous_demand : Null reply") - etree = ET.fromstring('' + comm_responce + '' ) + etree = ET.fromstring('' + comm_responce + '') rv = _et2d(etree) return rv # 11 - def get_demand_values(self, macid=None, interval="hour", frequency=None ) : + def get_demand_values(self, macid=None, interval="hour", frequency=None) : """ Send the GET_DEMAND_VALUES command get a series of instantaneous demand values @@ -238,7 +237,7 @@ class Eagle(object) : comm_responce = self._send_soc_comm("get_demand_values", **kwargs) if comm_responce is None: raise RainEagleResponseError("get_demand_values : Null reply") - etree = ET.fromstring('' + comm_responce + '' ) + etree = ET.fromstring('' + comm_responce + '') rv = _et2d(etree) return rv @@ -256,10 +255,10 @@ class Eagle(object) : if interval not in ['day', 'week', 'month', 'year'] : raise ValueError("get_summation_values interval must be 'day', 'week', 'month' or 'year'") comm_responce = self._send_soc_comm("get_summation_values", - MacId=macid, Interval=interval ) + MacId=macid, Interval=interval) if comm_responce is None: raise RainEagleResponseError("get_summation_values : Null reply") - etree = ET.fromstring('' + comm_responce + '' ) + etree = ET.fromstring('' + comm_responce + '') rv = _et2d(etree) return rv @@ -282,7 +281,7 @@ class Eagle(object) : MacId=macid, Frequency=frequency, Duration=duration) if comm_responce is None: raise RainEagleResponseError("set_fast_poll : Null reply") - etree = ET.fromstring('' + comm_responce + '' ) + etree = ET.fromstring('' + comm_responce + '') rv = _et2d(etree) return rv @@ -299,13 +298,13 @@ class Eagle(object) : comm_responce = self._send_soc_comm("get_fast_poll_status", MacId=macid) if comm_responce is None: return None - etree = ET.fromstring('' + comm_responce + '' ) + etree = ET.fromstring('' + comm_responce + '') rv = _et2d(etree) - return rv + return rv # 17 - def get_history_data(self, macid=None, starttime="0x00000000", endtime=None, frequency=None ) : + 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 ( socket command api ) @@ -327,7 +326,7 @@ class Eagle(object) : comm_responce = self._send_soc_comm("get_history_data", **kwargs) if comm_responce is None : raise RainEagleResponseError("get_history_data : Null reply") - etree = ET.fromstring('' + comm_responce + '' ) + etree = ET.fromstring('' + comm_responce + '') rv = _et2d(etree) return rv @@ -363,13 +362,13 @@ class Eagle(object) : "uploader_user_id" : "" "uploader_password" : "" "uploader_enabled" : "Y" - + See also set_cloud() to set current uploader cloud config """ comm_responce = self._send_http_comm("get_uploader") return json.loads(comm_responce) - - + + def set_message_read(self) : """ On Success returns dict with the values : @@ -406,27 +405,27 @@ class Eagle(object) : def get_usage_data(self) : """ Get current demand usage summation - + On Success returns dict with the values (example): - 'demand' : '0.4980', - 'demand_timestamp' : '1394505386', - 'demand_units' : 'kW', - 'message_confirm_required' : 'N', - 'message_confirmed' : 'N', - 'message_id' : '0', - 'message_priority' : '', - 'message_queue' : active', - 'message_read' : 'Y', - 'message_text' : '', - 'message_timestamp' : '946684800', - 'meter_status' : 'Connected', - 'price' : '0.1400', - 'price_label' : 'Set by User', - 'price_units' : '$', - 'summation_delivered' : '2667.867', - 'summation_received' : '37.283', - 'summation_units' : 'kWh', - 'usage_timestamp' : '1394505386'} + 'demand' : '0.4980' + 'demand_timestamp' : '1394505386' + 'demand_units' : 'kW' + 'message_confirm_required' : 'N' + 'message_confirmed' : 'N' + 'message_id' : '0' + 'message_priority' : '' + 'message_queue' : active' + 'message_read' : 'Y' + 'message_text' : '' + 'message_timestamp' : '946684800' + 'meter_status' : 'Connected' + 'price' : '0.1400' + 'price_label' : 'Set by User' + 'price_units' : '$' + 'summation_delivered' : '2667.867' + 'summation_received' : '37.283' + 'summation_units' : 'kWh' + 'usage_timestamp' : '1394505386' """ comm_responce = self._send_http_comm("get_usage_data") @@ -434,7 +433,7 @@ class Eagle(object) : def get_historical_data_alt(self, period="day") : - """ + """ get a series of summation values over an interval of time ( http command api ) @@ -442,49 +441,43 @@ class Eagle(object) : period day|week|month|year On Success returns dict with the values (example): - 'data_period' 'day', - 'data_size' '14', - 'timestamp[0]' '1394422200', - 'timestamp[1]' '1394425800', - 'timestamp[2]' '1394429400', - 'timestamp[3]' '1394433000', - 'timestamp[4]' '1394436600', - 'timestamp[5]' '1394440200', - 'timestamp[6]' '1394443800', - 'timestamp[7]' '1394447400', - 'timestamp[8]' '1394451000', - 'timestamp[9]' '1394454600', - 'timestamp[10]' '1394458200', - 'timestamp[11]' '1394461800', - 'timestamp[12]' '1394465400', - 'timestamp[13]' '1394469000', - 'value[0]' '0.429', - 'value[1]' '0.426', - 'value[2]' '0.422', - 'value[3]' '0.627', - 'value[4]' '0.735', - 'value[5]' '0.193', - 'value[6]' '0.026', - 'value[7]' '-0.985', - 'value[8]' '-1.491', - 'value[9]' '-2.196'} - 'value[11]' '-1.868', - 'value[12]' '-1.330', - 'value[13]' '-0.870', - - """ - if period not in ['day', 'week', 'month', 'year'] : + 'data_period' 'day' + 'data_size' '14' + 'timestamp[0]' '1394422200' + 'timestamp[1]' '1394425800' + 'timestamp[2]' '1394429400' + 'timestamp[3]' '1394433000' + 'timestamp[4]' '1394436600' + 'timestamp[5]' '1394440200' + 'timestamp[6]' '1394443800' + 'timestamp[7]' '1394447400' + 'timestamp[8]' '1394451000' + 'timestamp[9]' '1394454600' + 'timestamp[10]' '1394458200' + 'timestamp[11]' '1394461800' + 'timestamp[12]' '1394465400' + 'timestamp[13]' '1394469000' + 'value[0]' '0.429' + 'value[1]' '0.426' + 'value[2]' '0.422' + 'value[3]' '0.627' + 'value[4]' '0.735' + 'value[5]' '0.193' + 'value[6]' '0.026' + 'value[7]' '-0.985' + 'value[8]' '-1.491' + 'value[9]' '-2.196' + 'value[11]' '-1.868' + 'value[12]' '-1.330' + 'value[13]' '-0.870' + + """ + if period not in ['day', 'week', 'month', 'year'] : raise ValueError("get_historical_data_alt period must be one of day|week|month|year") comm_responce = self._send_http_comm("get_historical_data", Period=period) return json.loads(comm_responce) - def get_usage_data(self) : - """ - """ - comm_responce = self._send_http_comm("get_usage_data") - return json.loads(comm_responce) - def get_setting_data(self) : """ get settings data @@ -528,13 +521,12 @@ class Eagle(object) : On Success returns dict with the value : 'timezone_localTime': '1394527011' - 'timezone_olsonName': 'UTC/GMT', + 'timezone_olsonName': 'UTC/GMT' 'timezone_status': '2' 'timezone_utcOffset': 'UTC' 'timezone_utcTime': '1394527011' 'timezone_status': 'success' - """ comm_responce = self._send_http_comm("get_timezone") return json.loads(comm_responce) @@ -544,7 +536,7 @@ class Eagle(object) : get time source for device On Success returns dict with value 'internet' or 'meter' : - 'time_source': 'internet'} + 'time_source': 'internet' """ comm_responce = self._send_http_comm("get_time_source") return json.loads(comm_responce) @@ -592,10 +584,10 @@ class Eagle(object) : get price for kWh On Success returns (example): - price': '0.1300', + price': '0.1300' price_label': 'Set by User' or '--' - price_timestamp': '1394524458', - price_units': '$'} + price_timestamp': '1394524458' + price_units': '$' returns empty dict on Error """ @@ -616,21 +608,22 @@ class Eagle(object) : if isinstance(price, str) and price.startswith('$') : price = float(price.lstrip('$')) - if not isinstance(price, (int, long, float) ) : + if not isinstance(price, (int, long, float)) : raise ValueError("set_price price arg must me a int, long or float") - if ( price <= 0 ): + if (price <= 0): raise ValueError("set_price price arg greater then 0") trailing_digits = 0 multiplier = 1 - while (((price * multiplier) != (floor(price * multiplier))) and (trailing_digits < 7) ) : + while (((price * multiplier) != (floor(price * multiplier))) and (trailing_digits < 7)) : trailing_digits += 1 multiplier *= 10 - price_adj = "{:#x}".format( int(price * multiplier) ) - tdigits = "{:#x}".format( trailing_digits ) + price_adj = "{:#x}".format(int(price * multiplier)) + tdigits = "{:#x}".format(trailing_digits) - comm_responce = self._send_http_comm("set_price", Price=price_adj, TrailingDigits=tdigits) + comm_responce = self._send_http_comm("set_price", + Price=price_adj, TrailingDigits=tdigits) return json.loads(comm_responce) @@ -642,8 +635,8 @@ class Eagle(object) : 'set_price_status': 'success' """ comm_responce = self._send_http_comm("set_price", - Price="0xFFFFFFFF", - TrailingDigits="0x00") + Price="0xFFFFFFFF", + TrailingDigits="0x00") return json.loads(comm_responce) # def set_multiplier_divisor(self, multiplier=1, divisor=1) : @@ -671,7 +664,6 @@ class Eagle(object) : # return json.loads(comm_responce) - def cloud_reset(self) : """ cloud_reset : Clear Cloud Configuration @@ -722,22 +714,19 @@ class Eagle(object) : password = "" comm_responce = self._send_http_comm("set_cloud", - Provider="manual", - Protocol=protocol, HostName=hostname, - Url=url, Port=port, - AuthCode=authcode, Email=email, - UserId=userid, Password=password) + Provider="manual", + Protocol=protocol, HostName=hostname, + Url=url, Port=port, + AuthCode=authcode, Email=email, + UserId=userid, Password=password) return json.loads(comm_responce) - - - - # Support functions def _connect(self) : - self.soc = socket.create_connection( (self.addr, self.port), self.timeout) + self.soc = socket.create_connection( + (self.addr, self.port), self.timeout) def _disconnect(self): try : @@ -747,7 +736,6 @@ class Eagle(object) : except IOError : pass - def _send_http_comm(self, cmd, **kwargs): print "\n\n_send_http_comm : ", cmd diff --git a/bin/get_meter_status.py b/bin/get_meter_status.py deleted file mode 100755 index 6d8d6f8..0000000 --- a/bin/get_meter_status.py +++ /dev/null @@ -1,124 +0,0 @@ -#!/usr/local/bin/python2.7 -""" - A simple script get current meter values -""" - -__author__ = "Peter Shipley" - -import sys -sys.path.append('/usr/home/shipley/Projects/Eagle') # temp - - -# import RainEagle -from RainEagle import Eagle, to_epoch_1970 -import time -from pprint import pprint -import json - -last_delivered = 0 -debug = 0 - - -def main() : - eg = Eagle( debug=debug , addr="10.1.1.39") - # timeout=45, - - # print "\nlist_devices :" - # r = eg.list_devices() - # print "pprint 2" - # pprint(r) - - - - print "\nget_device_data :" - r = eg.get_device_data() - print - - # pprint(r['InstantaneousDemand']) - print_instantdemand( r['InstantaneousDemand']) - print - - # pprint(r['CurrentSummation']) - print_currentsummation(r['CurrentSummation']) - print - - exit(0) - -def twos_comp(val, bits=32): - """compute the 2's compliment of int value val""" - if( (val&(1<<(bits-1))) != 0 ): - val = val - (1< 0x7FFFFFFF: - demand -= 0x100000000 - - # print "Multiplier=", multiplier, "Divisor=", divisor, "Demand=", demand - - if multiplier == 0 : - multiplier=1 - - if divisor == 0 : - divisor=1 - - reading = (demand * multiplier) / float (divisor ) - - print time.asctime(time.localtime(time_stamp)), " : " - print "\tDemand=", reading, "Kw" - print "\tAmps = {:.3f}".format( ((reading * 1000) / 240) ) - - - -def print_reading(eg, rd) : - for dat in rd['Reading'] : - the_time = time.asctime(time.localtime( to_epoch_1970(dat['TimeStamp']) ) ) - print the_time, "Type=", dat['Type'], "Value=", dat['Value'] - -# -if __name__ == "__main__": - # import __main__ - # print(__main__.__file__) - # print("syntax ok") - main() - exit(0) - - diff --git a/bin/meter_status.py b/bin/meter_status.py new file mode 100755 index 0000000..1857504 --- /dev/null +++ b/bin/meter_status.py @@ -0,0 +1,105 @@ +#!/usr/local/bin/python2.7 +""" + A simple script get current meter values +""" + +__author__ = "Peter Shipley" + +import sys +sys.path.append('/usr/home/shipley/Projects/Eagle') # temp + + +# import RainEagle +from RainEagle import Eagle, to_epoch_1970 +import time +from pprint import pprint + +debug = 0 + +def main() : + eg = Eagle( debug=debug , addr="10.1.1.39") + # timeout=45, + + r = eg.get_device_data() + + print_instantdemand( r['InstantaneousDemand']) + print + + print_currentsummation(r['CurrentSummation']) + print + + exit(0) + +def twos_comp(val, bits=32): + """compute the 2's compliment of int value val""" + if( (val&(1<<(bits-1))) != 0 ): + val = val - (1< 0x7FFFFFFF: + demand -= 0x100000000 + + if multiplier == 0 : + multiplier = 1 + + if divisor == 0 : + divisor = 1 + + reading = (demand * multiplier) / float (divisor ) + + print "{0:s} : ".format(time.asctime(time.localtime(time_stamp))) + print "\tDemand = {0:{width}.3f} Kw".format(reading, width=10) + print "\tAmps = {0:{width}.3f}".format( ((reading * 1000) / 240), width=10 ) + + +# +if __name__ == "__main__": + # import __main__ + # print(__main__.__file__) + # print("syntax ok") + main() + exit(0) + + diff --git a/doc.txt b/doc.txt index 49d5bc2..4076668 100644 --- a/doc.txt +++ b/doc.txt @@ -273,84 +273,12 @@ CLASSES | On Error returns dict with value : | 'set_time_source_status': 'invalid source name' | - | ---------------------------------------------------------------------- - | Data descriptors defined here: - | - | __dict__ - | dictionary for instance variables (if defined) - | - | __weakref__ - | list of weak references to the object (if defined) class RainEagleResponseError(exceptions.RuntimeError) | General exception for responce errors | from Rainforest Automation EAGLE (RFA-Z109) | - | Method resolution order: - | RainEagleResponseError - | exceptions.RuntimeError - | exceptions.StandardError - | exceptions.Exception - | exceptions.BaseException - | __builtin__.object - | - | Data descriptors defined here: - | - | __weakref__ - | list of weak references to the object (if defined) - | - | ---------------------------------------------------------------------- - | Methods inherited from exceptions.RuntimeError: - | - | __init__(...) - | x.__init__(...) initializes x; see help(type(x)) for signature - | - | ---------------------------------------------------------------------- - | Data and other attributes inherited from exceptions.RuntimeError: - | - | __new__ = - | T.__new__(S, ...) -> a new object with type S, a subtype of T - | - | ---------------------------------------------------------------------- - | Methods inherited from exceptions.BaseException: - | - | __delattr__(...) - | x.__delattr__('name') <==> del x.name - | - | __getattribute__(...) - | x.__getattribute__('name') <==> x.name - | - | __getitem__(...) - | x.__getitem__(y) <==> x[y] - | - | __getslice__(...) - | x.__getslice__(i, j) <==> x[i:j] - | - | Use of negative indices is not supported. - | - | __reduce__(...) - | - | __repr__(...) - | x.__repr__() <==> repr(x) - | - | __setattr__(...) - | x.__setattr__('name', value) <==> x.name = value - | - | __setstate__(...) - | - | __str__(...) - | x.__str__() <==> str(x) - | - | __unicode__(...) - | - | ---------------------------------------------------------------------- - | Data descriptors inherited from exceptions.BaseException: - | - | __dict__ - | - | args | - | message DATA __all__ = ['Eagle', 'RainEagleResponseError', 'to_epoch_1970, to_epoch... diff --git a/setup.py b/setup.py index 035f6c1..f9059fd 100644 --- a/setup.py +++ b/setup.py @@ -33,11 +33,11 @@ setup( author='Peter Shipley', author_email='Peter.Shipley@gmail.com', packages=find_packages(), - scripts=[ 'binbin/get_meter_status.py', 'bin/plot_power.py' ] - data_files=[ + scripts=[ 'bin/meter_status.py', 'bin/plot_power.py' ], + data_files=[ ], # ('examples', ['bin/isy_find.py', 'bin/isy_progs.py', # 'bin/isy_log.py', 'bin/isy_net_wol.py']), - ('bin', ['bin/isy_nodes.py', 'bin/isy_var.py']) ], +# ('bin', ['bin/isy_nodes.py', 'bin/isy_var.py']) ], url='https://github.com/evilpete/RainEagle', license='BSD', description='Python Class for utilizing the Rainforest Automation Eagle ( RFA-Z109 ) socket API.',