diff --git a/RainEagle/EagleClass.py b/RainEagle/EagleClass.py
index 4341de2..8b49cbc 100644
--- a/RainEagle/EagleClass.py
+++ b/RainEagle/EagleClass.py
@@ -9,13 +9,32 @@ import sys
import os
import time
import xml.etree.ElementTree as ET
+import urllib
+import urllib2
+from math import floor
+from urlparse import urlparse
+import json
+
+
from pprint import pprint
-
+api_arg_format = {
+
+}
-__all__ = ['Eagle']
+__all__ = ['Eagle', 'to_unix_time']
+
+def to_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)
def _et2d(et) :
@@ -60,6 +79,19 @@ def _et2d(et) :
d[child.tag] = child.text
return d
+ def _tohex(n, width=10) :
+ """ convert arg to string with hex representation if possible"""
+ if isinstance(n, str) :
+ if n.isdigit() :
+ return "{:#{width}x}".format(int(n), width=width)
+ else :
+ return n
+ if isinstance(n, (int, long) ) :
+ return "{:#{width}x}".format(n, width=width)
+ if isinstance(n, float) :
+ return "{:#{width}x}".format(int(n), width=width)
+ return n
+
#
@@ -106,10 +138,10 @@ class Eagle(object) :
-# commands as class funtions
+# socket commands as class functions
def list_devices(self):
- comm_responce = self._send_comm("list_devices")
+ comm_responce = self._send_soc_comm("list_devices")
if self.debug :
print "comm_responce =", comm_responce
if comm_responce == None:
@@ -125,7 +157,7 @@ class Eagle(object) :
""" 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)
+ comm_responce = self._send_soc_comm("get_device_data", MacId=macid)
if comm_responce == None:
return None
etree = ET.fromstring('' + comm_responce + '' )
@@ -142,7 +174,7 @@ class Eagle(object) :
"""
if macid == None :
macid = self.macid
- comm_responce = self._send_comm("get_instantaneous_demand",
+ comm_responce = self._send_soc_comm("get_instantaneous_demand",
MacId=macid)
if comm_responce == None:
return None
@@ -162,10 +194,12 @@ class Eagle(object) :
"""
if macid == None :
macid = self.macid
+ if interval not in ['hour', 'day', 'week' ] :
+ raise ValueError("set_time_source interval must be 'hour', 'day' or 'week' ")
kwargs = {"MacId": macid, "Interval": interval}
if frequency :
- kwargs["Frequency"] = frequency
- comm_responce = self._send_comm("get_demand_values", **kwargs)
+ kwargs["Frequency"] = str(frequency)
+ comm_responce = self._send_soc_comm("get_demand_values", **kwargs)
if comm_responce == None:
return None
etree = ET.fromstring('' + comm_responce + '' )
@@ -183,7 +217,9 @@ class Eagle(object) :
"""
if macid == None :
macid = self.macid
- comm_responce = self._send_comm("get_summation_values",
+ if interval not in ['day', 'week', 'month', 'year'] :
+ raise ValueError("set_time_source interval must be 'day', 'week', 'month' or 'year'")
+ comm_responce = self._send_soc_comm("get_summation_values",
MacId=macid, Interval=interval )
if comm_responce == None:
return None
@@ -203,12 +239,10 @@ class Eagle(object) :
"""
if macid == None :
macid = self.macid
- if isinstance(frequency, int) :
- frequency = "{:#04x}".format(m)
- if isinstance(duration, int) :
- frequency = "{:#04x}".format(m)
+ frequency = _tohex(frequency, 4)
+ duration = _tohex(duration, 4)
- comm_responce = self._send_comm("get_instantaneous_demand",
+ comm_responce = self._send_soc_comm("get_instantaneous_demand",
MacId=macid, Frequency=frequency, Duration=duration)
if comm_responce == None:
return None
@@ -226,7 +260,7 @@ class Eagle(object) :
"""
if macid == None :
macid = self.macid
- comm_responce = self._send_comm("get_fast_poll_status", MacId=macid)
+ comm_responce = self._send_soc_comm("get_fast_poll_status", MacId=macid)
if comm_responce == None:
return None
etree = ET.fromstring('' + comm_responce + '' )
@@ -247,12 +281,13 @@ class Eagle(object) :
"""
if macid == None :
macid = self.macid
- kwargs = {"MacId": macid, "StartTime": starttime}
+ kwargs = {"MacId": macid,}
+ kwargs["StartTime"] = _tohex(starttime, 10)
if endtime :
- kwargs["EndTime"] = endtime
+ kwargs["EndTime"] = _tohex(endtime, 10)
if frequency :
- kwargs["Frequency"] = frequency
- comm_responce = self._send_comm("get_history_data", **kwargs)
+ kwargs["Frequency"] = _tohex(endtime, 6)
+ comm_responce = self._send_soc_comm("get_history_data", **kwargs)
if comm_responce == None :
return None
etree = ET.fromstring('' + comm_responce + '' )
@@ -260,7 +295,165 @@ class Eagle(object) :
return rv
- # Support functions
+# http commands as class functions
+
+ def get_setting_data(self) :
+ comm_responce = self._send_http_comm("get_setting_data")
+ return comm_responce
+
+ def get_device_config(self) :
+ comm_responce = self._send_http_comm("get_device_config")
+ return comm_responce
+
+ def get_timezone(self) :
+ comm_responce = self._send_http_comm("get_timezone")
+ return comm_responce
+
+ def get_time_source(self, macid=None) :
+ comm_responce = self._send_http_comm("get_time_source")
+ return comm_responce
+
+ def set_remote_management(self, macid=None, status=None) :
+ """ set_remote_management
+ enabling ssh & vpn
+
+ args:
+ status yes|no
+
+ """
+ if status not in ['yes', 'no'] :
+ raise ValueError("set_remote_management status must be 'yes' or 'no'")
+ comm_responce = self._send_http_comm("set_remote_management", Status=status)
+ return comm_responce
+
+
+ def set_time_source(self, macid=None, source=None) :
+ """ set_time_source
+ set time source
+
+ args:
+ source meter|internet
+ """
+ if status not in ['meter', 'internet'] :
+ raise ValueError("set_time_source Source must be 'meter' or 'internet'")
+ comm_responce = self._send_http_comm("set_time_source", Source=source)
+ return comm_responce
+
+ def get_price(self) :
+ """
+ get price for kWh
+ """
+ comm_responce = self._send_http_comm("get_price")
+ return comm_responce
+
+ def set_price(self, price) :
+ """
+ Set price manualy
+
+ args:
+ price Price/kWh
+ """
+ #if isinstance(price, str) :
+ # price = float(price.lstrip('$'))
+
+ if not isinstance(price, (int, long, float) ) :
+ raise ValueError("set_price price arg must me a int, long or float")
+
+ trailing_digits = 0
+ multiplier = 1
+ 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 )
+
+ comm_responce = self._send_http_comm("set_price", Price=price_adj, TrailingDigits=tdigits)
+ return comm_responce
+
+
+ def set_price_auto(self) :
+ """
+ Set Price from Meter
+ """
+ comm_responce = self._send_http_comm("set_price",
+ Price="0xFFFFFFFF",
+ TrailingDigits="0x00")
+ return comm_responce
+
+ def factory_reset(self) :
+ """
+ Factory Reset
+ """
+ comm_responce = self._send_http_comm("factory_reset")
+ return comm_responce
+
+
+# def disconnect_meter(self) :
+# """
+# disconnect from Smart Meter
+# """
+# comm_responce = self._send_http_comm("disconnect_meter")
+# return comm_responce
+
+
+
+ def cloud_reset(self) :
+ """
+ cloud_reset : Clear Cloud Configuration
+ """
+ comm_responce = self._send_http_comm("cloud_reset")
+ return comm_responce
+
+
+ def set_cloud(self, url) :
+ """
+ set cloud Url
+ """
+ if url.__len__() > 200 :
+ raise ValueError("Max URL length is 200 characters long.\n")
+
+ urlp = urlparse(url)
+
+ if urlp.port :
+ port = "{:#4x}".format(urlp.port)
+ else :
+ port = "0x00"
+
+ hostname = urlp.hostname
+
+ if urlp.scheme :
+ protocol = urlp.scheme
+ else :
+ protocol = "http"
+
+ url = urlp.path
+
+
+ if urlp.username :
+ userid = urlp.username
+ else :
+ userid = ""
+
+ if urlp.password :
+ password = urlp.password
+ else :
+ password = ""
+
+ comm_responce = self._send_http_comm("set_cloud",
+ Provider="manual",
+ Protocol=protocol, HostName=hostname,
+ Url=url, Port=port,
+ AuthCode="", Email="",
+ UserId=userid, Password=password)
+
+ return comm_responce
+
+
+
+
+
+# Support functions
def _connect(self) :
self.soc = socket.create_connection( (self.addr, self.port), 10)
@@ -274,7 +467,30 @@ class Eagle(object) :
pass
- def _send_comm(self, cmd, **kwargs):
+ def _send_http_comm(self, cmd, **kwargs):
+
+ print "\n\n_send_http_comm : ", cmd
+
+ commstr = "\n"
+ commstr += "{0!s}\n".format(cmd)
+ commstr += "{0!s}\n".format(self.macid)
+ for k, v in kwargs.items() :
+ commstr += "<{0}>{1!s}{0}>\n".format(k, v)
+ commstr += "\n"
+
+ print(commstr)
+
+ url = "http://{0}/cgi-bin/cgi_manager".format(self.addr)
+
+ req = urllib2.Request(url, commstr)
+ response = urllib2.urlopen(req)
+ the_page = response.read()
+
+ return the_page
+
+
+
+ def _send_soc_comm(self, cmd, **kwargs):
if cmd == "set_fast_poll" :
command_tag = "RavenCommand"
@@ -288,6 +504,7 @@ class Eagle(object) :
commstr += "<{0}>{1!s}{0}>\n".format(k, v)
commstr += "{0}>\n".format(command_tag)
replystr = ""
+ # buf_list = []
try:
self._connect()
@@ -305,6 +522,8 @@ class Eagle(object) :
if not buf:
break
replystr += buf
+ #buf_list.append(buf)
+ # replystr = ''.join(buf_list)
except Exception:
print("Unexpected error:", sys.exc_info()[0])
@@ -313,18 +532,9 @@ class Eagle(object) :
finally:
self._disconnect()
if self.debug > 1 :
- print "_send_comm replystr :\n", replystr
+ print "_send_soc_comm replystr :\n", replystr
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)