thank you dave. i’ll see how far i can get, and if you end up with any time to tinker with it it would be much appreciated.
thanks all
dtich wrote:thank you dave. i’ll see how far i can get, and if you end up with any time to tinker with it it would be much appreciated.
thanks all
#!/usr/bin/env python
# version: 0.3
# date: 2012-11-30
# author: Joerg Raedler joerg@j-raedler.de
# license: BSD
# purpose: make RPC to a Sunny WebBox, a monitoring system for solar plants
#
# http://www.sma.de/en/produkte/monitoring-systems/sunny-webbox.html
#
# Use the classes SunnyWebBoxHTTP or SunnyWebBoxUDPStream in your code
# or run this file as a script to test the classes. First parameter is
# the hostname or IP of the box. A password can be provided with an
# optional second parameter.
#
# Example: python SunnyWebBox.py 123.123.123.123 "foobar"
#
# Documentation on the RPC API can be found here:
#
# http://files.sma.de/dl/2585/SWebBoxRPC-BEN092713.pdf
#
import sys, json, hashlib
# handle python 2 and 3
if sys.version_info >= (3, 0):
py3 = True
def str2buf(s):
return bytes(s, 'latin1')
def buf2str(b):
return str(b, 'latin1')
else:
py3 = False
def str2buf(s):
return bytes(s)
def buf2str(b):
return unicode(b, 'latin1')
class Counter:
"""generate increasing numbers with every call - just for convenience"""
def __init__(self, start=0):
self.i = start
def __call__(self):
i = self.i
self.i += 1
return i
class SunnyWebBoxBase(object):
"""Communication with a 'Sunny WebBox', a monitoring system for solar plants.
This is an abstract base class, please use SunnyWebBoxHTTP or
SunnyWebBoxUDPStream instead!
"""
def __init__(self, host='192.168.0.98', password='*****'):
self.host = host
if password:
self.pwenc = hashlib.md5(password).hexdigest()
else:
self.pwenc = ''
self.count = Counter(1)
self.openConnection()
def openConnection(self):
raise Exception('Abstract base class, use child class instead!')
def newRequest(self, name='GetPlantOverview', withPW=False, **params):
"""return a new rpc request structure (dictionary)"""
r = {'version': '1.0', 'proc': name, 'format': 'JSON'}
r['id'] = str(self.count())
if withPW:
r['passwd'] = self.pwenc
if params:
r['params'] = params
return r
def _rpc(self, *args):
raise Exception('Abstract base class, use child class instead!')
def printOverview(self):
"""print a short overview of the plant data"""
for v in self.getPlantOverview():
print("%15s (%15s): %s %s" %
(v['name'], v['meta'], v['value'], v['unit']))
# wrapper methods for the RPC functions
def getPlantOverview(self):
res = self._rpc(self.newRequest('GetPlantOverview'))
return res['overview']
def getDevices(self):
res = self._rpc(self.newRequest('GetDevices'))
return res['devices']
def getProcessDataChannels(self, deviceKey):
res = self._rpc(self.newRequest('GetProcessDataChannels', device=deviceKey))
return res[deviceKey]
def getProcessData(self, channels):
res = self._rpc(self.newRequest('GetProcessData', devices=channels))
# reorder data structure: {devKey: {dict of channels}, ...}
# return {l['key']: l['channels'] for l in res['devices']}
r = {}
for l in res['devices']:
r[l['key']] = l['channels']
return r
def getParameterChannels(self, deviceKey):
res = self._rpc(self.newRequest('GetParameterChannels', withPW=True, device=deviceKey))
return res[deviceKey]
def getParameter(self, channels):
res = self._rpc(self.newRequest('GetParameter', withPW=True, devices=channels))
# reorder data structure: {devKey: {dict of channels}, ...}
# return {l['key']: l['channels'] for l in res['devices']}
r = {}
for l in res['devices']:
r[l['key']] = l['channels']
return r
def setParameter(self, *args):
raise Exception('Not yet implemented!')
class SunnyWebBoxHTTP(SunnyWebBoxBase):
"""Communication with a 'Sunny WebBox' via HTTP."""
def openConnection(self):
if py3:
from http.client import HTTPConnection
else:
from httplib import HTTPConnection
self.conn = HTTPConnection(self.host)
def _rpc(self, request):
"""send an rpc request as JSON object via http and read the result"""
js = json.dumps(request)
self.conn.request('POST', '/rpc', "RPC=%s" % js)
tmp = buf2str(self.conn.getresponse().read())
response = json.loads(tmp)
if response['id'] != request['id']:
raise Exception('RPC answer has wrong id!')
return response['result']
class SunnyWebBoxUDPStream(SunnyWebBoxBase):
"""Communication with a 'Sunny WebBox' via UDP Stream."""
def openConnection(self):
from socket import socket, AF_INET, SOCK_DGRAM
self.udpPort = 34268
self.ssock = socket(AF_INET, SOCK_DGRAM)
self.rsock = socket(AF_INET, SOCK_DGRAM)
self.rsock.bind(("", self.udpPort))
self.rsock.settimeout(100.0)
def _rpc(self, request):
"""send an rpc request as JSON object via UDP Stream and read the result"""
js = ''.join(i+'\0' for i in json.dumps(request, separators=(',',':')))
self.ssock.sendto(str2buf(js), (self.host, self.udpPort))
while True:
data, addr = self.rsock.recvfrom(10*1024)
if addr[0] == self.host:
break
tmp = buf2str(data).replace('\0', '')
response = json.loads(tmp)
if response['id'] != request['id']:
raise Exception('RPC answer has wrong id!')
return response['result']
if __name__ == '__main__':
# pw = ''
#ip = sys.argv[1]
#if len(sys.argv) > 2:
# pw = sys.argv[2]
ip = "192.168.0.98"
pw = "******"
swb = SunnyWebBoxHTTP(ip, password=pw)
# swb = SunnyWebBoxUDPStream(ip, password=pw)
print('###### Overview:')
swb.printOverview()
for d in swb.getDevices():
devKey = d['key']
print("\n #### Device %s (%s):" % (devKey, d['name']))
print("\n ## Process data:")
channels = swb.getProcessDataChannels(devKey)
data = swb.getProcessData([{'key':devKey, 'channels':channels}])
for c in data[devKey]:
print(" %15s (%15s): %s %s" %
(c['name'], c['meta'], c['value'], c['unit']))
print("\n ## Parameters:")
channels = swb.getParameterChannels(devKey)
data = swb.getParameter([{'key':devKey, 'channels':channels}])
for c in data[devKey]:
print(" %15s (%15s): %s %s" %
(c['name'], c['meta'], c['value'], c['unit']))
###### Overview:
GriPwr ( GriPwr): 2734 W
GriEgyTdy ( GriEgyTdy): 45.728 kWh
GriEgyTot ( GriEgyTot): 55805.878 kWh
OpStt ( OpStt):
Msg ( Msg):
#### Device WR8KU002:2002099375 (WR8KU002:2002099375):
## Process data:
Backup State ( Backup State): -----
CO2 saved ( CO2 saved): 94870.000 lbs
Error ( Error): -------
E-Total ( E-Total): 55805.878 kWh
Fac ( Fac): 60.010 Hz
Grid Type ( Grid Type): 240V w/o N
h-On ( h-On): 22557.7320823962 h
h-Total ( h-Total): 21499.3419977250 h
Iac ( Iac): 11.732 A
Ipv ( Ipv): 9.736 A
Mode ( Mode): Mpp
Pac ( Pac): 2734 W
Power On ( Power On): 6822
Serial Number ( Serial Number): 2002099375
Temperature ( Temperature): 60.3 degC
Vac ( Vac): 233.0 V
Vpv ( Vpv): 291 V
## Parameters:
Backup Mode ( Backup Mode): Off
CO2-Fact ( CO2-Fact): 1.7 lbs/kWh
Default ( Default): USA/UL1741/2005
E_Total ( E_Total): 55805.48 kWh
Fac-delta- ( Fac-delta-): 0.69 Hz
Fac-delta ( Fac-delta ):
Fac-Limit delta (Fac-Limit delta): 2 Hz
Fac-MinTripTime (Fac-MinTripTime): 0.16 s
Fac-Start delta (Fac-Start delta): 1 Hz
Fan-Test ( Fan-Test): 0
h_Total ( h_Total): 21499.21 h
KI-Wind-Reg ( KI-Wind-Reg): 0.005
KP-Wind-Reg ( KP-Wind-Reg): 0.02
Memory Function (Memory Function): No function
Operating mode ( Operating mode): Mpp-Operation
Plimit ( Plimit): 8100 W
Pmax ( Pmax): 8100 W
PowerBalancer ( PowerBalancer): Off
PowerBalMax ( PowerBalMax): 8000 W
P-Wind-Mid ( P-Wind-Mid): 2000 W
P-Wind-Ramp ( P-Wind-Ramp): 1000 W/s
SMA-SN ( SMA-SN): 2002099375
Software-BFR ( Software-BFR): 1.18 Version
Software-SRR ( Software-SRR): 1.18 Version
T-Max-Fan ( T-Max-Fan): 90 degC
T-Start ( T-Start): 10 s
T-Start-Fan ( T-Start-Fan): 70 degC
T-Stop ( T-Stop): 2 s
T-Stop-Fan ( T-Stop-Fan): 55 degC
Vac-Max ( Vac-Max): 10 %
Vac-Max-Fast ( Vac-Max-Fast): 20 %
Vac-Max-Recnct ( Vac-Max-Recnct): 5.83 %
Vac-Min ( Vac-Min): 12 %
Vac-Min-Fast ( Vac-Min-Fast): 50 %
Vac-Min-Recnct ( Vac-Min-Recnct): 11.7 %
V-Const Setval ( V-Const Setval): 600 V
VdcWindMax ( VdcWindMax): 550 V
VdcWindMid ( VdcWindMid): 380 V
VdcWindStart ( VdcWindStart): 310 V
Vpv-Max ( Vpv-Max): 600 V
Vpv-Start ( Vpv-Start): 365 V
indigo.variable.updateValue(VARIABLE_ID, "VALUE_STRING")
pac = 2734
indigo.updateValue(1958563501, Pac)
if (v['name'] == 'GriEgyTdy'):
indigo.updateValue(1958563501, v['value'])
swb = SunnyWebBoxHTTP(ip, password=pw)
print(unicode(swb))
indigo.server.logt(unicode(swb))
#! /usr/bin/env python
# -*- coding: utf-8 -*-
#!/usr/bin/env python
# version: 0.3
# date: 2012-11-30
# author: Joerg Raedler joerg@j-raedler.de
# license: BSD
# purpose: make RPC to a Sunny WebBox, a monitoring system for solar plants
#
# http://www.sma.de/en/produkte/monitoring-systems/sunny-webbox.html
#
# Use the classes SunnyWebBoxHTTP or SunnyWebBoxUDPStream in your code
# or run this file as a script to test the classes. First parameter is
# the hostname or IP of the box. A password can be provided with an
# optional second parameter.
#
# Example: python SunnyWebBox.py 123.123.123.123 "foobar"
#
# Documentation on the RPC API can be found here:
#
# http://files.sma.de/dl/2585/SWebBoxRPC-BEN092713.pdf
#
import sys, json, hashlib
# handle python 2 and 3
if sys.version_info >= (3, 0):
py3 = True
def str2buf(s):
return bytes(s, 'latin1')
def buf2str(b):
return str(b, 'latin1')
else:
py3 = False
def str2buf(s):
return bytes(s)
def buf2str(b):
return unicode(b, 'latin1')
class Counter:
"""generate increasing numbers with every call - just for convenience"""
def __init__(self, start=0):
self.i = start
def __call__(self):
i = self.i
self.i += 1
return i
class SunnyWebBoxBase(object):
"""Communication with a 'Sunny WebBox', a monitoring system for solar plants.
This is an abstract base class, please use SunnyWebBoxHTTP or
SunnyWebBoxUDPStream instead!
"""
def __init__(self, host='192.168.0.98', password='*****'):
self.host = host
if password:
self.pwenc = hashlib.md5(password).hexdigest()
else:
self.pwenc = ''
self.count = Counter(1)
self.openConnection()
def openConnection(self):
raise Exception('Abstract base class, use child class instead!')
def newRequest(self, name='GetPlantOverview', withPW=False, **params):
"""return a new rpc request structure (dictionary)"""
r = {'version': '1.0', 'proc': name, 'format': 'JSON'}
r['id'] = str(self.count())
if withPW:
r['passwd'] = self.pwenc
if params:
r['params'] = params
return r
def _rpc(self, *args):
raise Exception('Abstract base class, use child class instead!')
def printOverview(self):
"""print a short overview of the plant data"""
for v in self.getPlantOverview():
print("%15s (%15s): %s %s" %
(v['name'], v['meta'], v['value'], v['unit']))
# wrapper methods for the RPC functions
def getPlantOverview(self):
res = self._rpc(self.newRequest('GetPlantOverview'))
return res['overview']
def getDevices(self):
res = self._rpc(self.newRequest('GetDevices'))
return res['devices']
def getProcessDataChannels(self, deviceKey):
res = self._rpc(self.newRequest('GetProcessDataChannels', device=deviceKey))
return res[deviceKey]
def getProcessData(self, channels):
res = self._rpc(self.newRequest('GetProcessData', devices=channels))
# reorder data structure: {devKey: {dict of channels}, ...}
# return {l['key']: l['channels'] for l in res['devices']}
r = {}
for l in res['devices']:
r[l['key']] = l['channels']
return r
def getParameterChannels(self, deviceKey):
res = self._rpc(self.newRequest('GetParameterChannels', withPW=True, device=deviceKey))
return res[deviceKey]
def getParameter(self, channels):
res = self._rpc(self.newRequest('GetParameter', withPW=True, devices=channels))
# reorder data structure: {devKey: {dict of channels}, ...}
# return {l['key']: l['channels'] for l in res['devices']}
r = {}
for l in res['devices']:
r[l['key']] = l['channels']
return r
def setParameter(self, *args):
raise Exception('Not yet implemented!')
class SunnyWebBoxHTTP(SunnyWebBoxBase):
"""Communication with a 'Sunny WebBox' via HTTP."""
def openConnection(self):
if py3:
from http.client import HTTPConnection
else:
from httplib import HTTPConnection
self.conn = HTTPConnection(self.host)
def _rpc(self, request):
"""send an rpc request as JSON object via http and read the result"""
js = json.dumps(request)
self.conn.request('POST', '/rpc', "RPC=%s" % js)
tmp = buf2str(self.conn.getresponse().read())
response = json.loads(tmp)
if response['id'] != request['id']:
raise Exception('RPC answer has wrong id!')
return response['result']
class SunnyWebBoxUDPStream(SunnyWebBoxBase):
"""Communication with a 'Sunny WebBox' via UDP Stream."""
def openConnection(self):
from socket import socket, AF_INET, SOCK_DGRAM
self.udpPort = 34268
self.ssock = socket(AF_INET, SOCK_DGRAM)
self.rsock = socket(AF_INET, SOCK_DGRAM)
self.rsock.bind(("", self.udpPort))
self.rsock.settimeout(100.0)
def _rpc(self, request):
"""send an rpc request as JSON object via UDP Stream and read the result"""
js = ''.join(i+'\0' for i in json.dumps(request, separators=(',',':')))
self.ssock.sendto(str2buf(js), (self.host, self.udpPort))
while True:
data, addr = self.rsock.recvfrom(10*1024)
if addr[0] == self.host:
break
tmp = buf2str(data).replace('\0', '')
response = json.loads(tmp)
if response['id'] != request['id']:
raise Exception('RPC answer has wrong id!')
return response['result']
if __name__ == '__main__':
# pw = ''
# ip = sys.argv[1]
# if len(sys.argv) > 2:
# pw = sys.argv[2]
ip = "192.168.0.98"
pw = "******"
swb = SunnyWebBoxHTTP(ip, password=pw)
# swb = SunnyWebBoxUDPStream(ip, password=pw)
# print('###### Overview:')
# swb.printOverview()
#
# for d in swb.getDevices():
# devKey = d['key']
# print("\n #### Device %s (%s):" % (devKey, d['name']))
#
# print("\n ## Process data:")
# channels = swb.getProcessDataChannels(devKey)
# data = swb.getProcessData([{'key':devKey, 'channels':channels}])
# for c in data[devKey]:
# print(" %15s (%15s): %s %s" %
# (c['name'], c['meta'], c['value'], c['unit']))
#
#
# print("\n ## Parameters:")
# channels = swb.getParameterChannels(devKey)
# data = swb.getParameter([{'key':devKey, 'channels':channels}])
# for c in data[devKey]:
# print(" %15s (%15s): %s %s" %
# (c['name'], c['meta'], c['value'], c['unit']))
print(unicode(swb))
Action Group sma webbox poll
Script Error webbox_poll_2.py: 'ServerInfo' object has no attribute 'logt'
Script Error Exception Traceback (most recent call shown last):
webbox_poll_2.py, line 214, at top level
AttributeError: 'ServerInfo' object has no attribute 'logt'
Jul 16, 2017, 10:26:08 AM
Action Group sma webbox poll
Script <__main__.SunnyWebBoxHTTP object at 0x10f133c10>
Received INSTEON "hvac/therm A" temperature changed to 77.0
#!/usr/bin/env python
# version: 0.3
# date: 2012-11-30
# author: Joerg Raedler joerg@j-raedler.de
# license: BSD
# purpose: make RPC to a Sunny WebBox, a monitoring system for solar plants
#
# http://www.sma.de/en/produkte/monitoring-systems/sunny-webbox.html
#
# Use the classes SunnyWebBoxHTTP or SunnyWebBoxUDPStream in your code
# or run this file as a script to test the classes. First parameter is
# the hostname or IP of the box. A password can be provided with an
# optional second parameter.
#
# Example: python SunnyWebBox.py 123.123.123.123 "foobar"
#
# Documentation on the RPC API can be found here:
#
# http://files.sma.de/dl/2585/SWebBoxRPC-BEN092713.pdf
#
import sys, json, hashlib
# INDIGO GLOBALS
global Pac, Mode, GriEgyTot, GriEgyTdy, GriPwr
# handle python 2 and 3
if sys.version_info >= (3, 0):
py3 = True
def str2buf(s):
return bytes(s, 'latin1')
def buf2str(b):
return str(b, 'latin1')
else:
py3 = False
def str2buf(s):
return bytes(s)
def buf2str(b):
return unicode(b, 'latin1')
class Counter:
"""generate increasing numbers with every call - just for convenience"""
def __init__(self, start=0):
self.i = start
def __call__(self):
i = self.i
self.i += 1
return i
class SunnyWebBoxBase(object):
"""Communication with a 'Sunny WebBox', a monitoring system for solar plants.
This is an abstract base class, please use SunnyWebBoxHTTP or
SunnyWebBoxUDPStream instead!
"""
def __init__(self, host='192.168.0.98', password='*****'):
self.host = host
if password:
self.pwenc = hashlib.md5(password).hexdigest()
else:
self.pwenc = ''
self.count = Counter(1)
self.openConnection()
def openConnection(self):
raise Exception('Abstract base class, use child class instead!')
def newRequest(self, name='GetPlantOverview', withPW=False, **params):
"""return a new rpc request structure (dictionary)"""
r = {'version': '1.0', 'proc': name, 'format': 'JSON'}
r['id'] = str(self.count())
if withPW:
r['passwd'] = self.pwenc
if params:
r['params'] = params
return r
def _rpc(self, *args):
raise Exception('Abstract base class, use child class instead!')
def printOverview(self):
"""print a short overview of the plant data"""
for v in self.getPlantOverview():
print("%15s (%15s): %s %s" %
(v['name'], v['meta'], v['value'], v['unit']))
# INDIGO UPDATE VARIABLES SECTION
if (v['name'] == 'GriEgyTdy'):
indigo.variable.updateValue(1822257245, v['value'])
if (v['name'] == 'GriEgyTot'):
indigo.variable.updateValue(1469286291, v['value'])
if (v['name'] == 'GriPwr'):
indigo.variable.updateValue(1958563501, v['value'])
#if (v['name'] == 'Mode'):
#indigo.variable.updateValue(789149473, v['value'])
# wrapper methods for the RPC functions
def getPlantOverview(self):
res = self._rpc(self.newRequest('GetPlantOverview'))
return res['overview']
def getDevices(self):
res = self._rpc(self.newRequest('GetDevices'))
return res['devices']
def getProcessDataChannels(self, deviceKey):
res = self._rpc(self.newRequest('GetProcessDataChannels', device=deviceKey))
return res[deviceKey]
def getProcessData(self, channels):
res = self._rpc(self.newRequest('GetProcessData', devices=channels))
# reorder data structure: {devKey: {dict of channels}, ...}
# return {l['key']: l['channels'] for l in res['devices']}
r = {}
for l in res['devices']:
r[l['key']] = l['channels']
return r
def getParameterChannels(self, deviceKey):
res = self._rpc(self.newRequest('GetParameterChannels', withPW=True, device=deviceKey))
return res[deviceKey]
def getParameter(self, channels):
res = self._rpc(self.newRequest('GetParameter', withPW=True, devices=channels))
# reorder data structure: {devKey: {dict of channels}, ...}
# return {l['key']: l['channels'] for l in res['devices']}
r = {}
for l in res['devices']:
r[l['key']] = l['channels']
return r
def setParameter(self, *args):
raise Exception('Not yet implemented!')
class SunnyWebBoxHTTP(SunnyWebBoxBase):
"""Communication with a 'Sunny WebBox' via HTTP."""
def openConnection(self):
if py3:
from http.client import HTTPConnection
else:
from httplib import HTTPConnection
self.conn = HTTPConnection(self.host)
def _rpc(self, request):
"""send an rpc request as JSON object via http and read the result"""
js = json.dumps(request)
self.conn.request('POST', '/rpc', "RPC=%s" % js)
tmp = buf2str(self.conn.getresponse().read())
response = json.loads(tmp)
if response['id'] != request['id']:
raise Exception('RPC answer has wrong id!')
return response['result']
class SunnyWebBoxUDPStream(SunnyWebBoxBase):
"""Communication with a 'Sunny WebBox' via UDP Stream."""
def openConnection(self):
from socket import socket, AF_INET, SOCK_DGRAM
self.udpPort = 34268
self.ssock = socket(AF_INET, SOCK_DGRAM)
self.rsock = socket(AF_INET, SOCK_DGRAM)
self.rsock.bind(("", self.udpPort))
self.rsock.settimeout(100.0)
def _rpc(self, request):
"""send an rpc request as JSON object via UDP Stream and read the result"""
js = ''.join(i+'\0' for i in json.dumps(request, separators=(',',':')))
self.ssock.sendto(str2buf(js), (self.host, self.udpPort))
while True:
data, addr = self.rsock.recvfrom(10*1024)
if addr[0] == self.host:
break
tmp = buf2str(data).replace('\0', '')
response = json.loads(tmp)
if response['id'] != request['id']:
raise Exception('RPC answer has wrong id!')
return response['result']
if __name__ == '__main__':
# pw = ''
#ip = sys.argv[1]
#if len(sys.argv) > 2:
# pw = sys.argv[2]
ip = "192.168.0.98"
pw = "*****"
swb = SunnyWebBoxHTTP(ip, password=pw)
# swb = SunnyWebBoxUDPStream(ip, password=pw)
print('###### Overview:')
swb.printOverview()
for d in swb.getDevices():
devKey = d['key']
print("\n #### Device %s (%s):" % (devKey, d['name']))
print("\n ## Process data:")
channels = swb.getProcessDataChannels(devKey)
data = swb.getProcessData([{'key':devKey, 'channels':channels}])
for c in data[devKey]:
print(" %15s (%15s): %s %s" %
(c['name'], c['meta'], c['value'], c['unit']))
print("\n ## Parameters:")
channels = swb.getParameterChannels(devKey)
data = swb.getParameter([{'key':devKey, 'channels':channels}])
for c in data[devKey]:
print(" %15s (%15s): %s %s" %
(c['name'], c['meta'], c['value'], c['unit']))
# indigo.variables[1822257245] # "PV_EToday"
# indigo.variables[1469286291] # "PV_ETotal"
# indigo.variables[789149473] # "PV_Mode"
# indigo.variables[1958563501] # "PV_Pac"
# indigo.variables[532315452] # "PV_Overview"
# global Pac, Mode, GriEgyTot, GriEgyTdy
# Pac =
#indigo.variable.updateValue(1958563501, "Pac")
#indigo.variable.updateValue(1958563501, str(value of variable "Pac" as string))
#indigo.variable.updateValue(789149473, "Mode")
#indigo.variable.updateValue(1469286291, "GriEgyTot")
#indigo.variable.updateValue(1822257245, "GriEgyTdy")
#indigo.variable.updateValue(532315452, overview)
# indigo.server.log("The variable had a value of 'true'")
Jul 16, 2017, 10:54:18 AM
Action Group sma webbox poll
Script <__main__.SunnyWebBoxHTTP object at 0x108039b10>
#! /usr/bin/env python
# -*- coding: utf-8 -*-
#!/usr/bin/env python
# version: 0.3
# date: 2012-11-30
# author: Joerg Raedler joerg@j-raedler.de
# license: BSD
# purpose: make RPC to a Sunny WebBox, a monitoring system for solar plants
#
# http://www.sma.de/en/produkte/monitoring-systems/sunny-webbox.html
#
# Use the classes SunnyWebBoxHTTP or SunnyWebBoxUDPStream in your code
# or run this file as a script to test the classes. First parameter is
# the hostname or IP of the box. A password can be provided with an
# optional second parameter.
#
# Example: python SunnyWebBox.py 123.123.123.123 "foobar"
#
# Documentation on the RPC API can be found here:
#
# http://files.sma.de/dl/2585/SWebBoxRPC-BEN092713.pdf
#
import sys, json, hashlib
# handle python 2 and 3
if sys.version_info >= (3, 0):
py3 = True
def str2buf(s):
return bytes(s, 'latin1')
def buf2str(b):
return str(b, 'latin1')
else:
py3 = False
def str2buf(s):
return bytes(s)
def buf2str(b):
return unicode(b, 'latin1')
class Counter:
"""generate increasing numbers with every call - just for convenience"""
def __init__(self, start=0):
self.i = start
def __call__(self):
i = self.i
self.i += 1
return i
class SunnyWebBoxBase(object):
"""Communication with a 'Sunny WebBox', a monitoring system for solar plants.
This is an abstract base class, please use SunnyWebBoxHTTP or
SunnyWebBoxUDPStream instead!
"""
def __init__(self, host='192.168.0.98', password='*****'):
self.host = host
if password:
self.pwenc = hashlib.md5(password).hexdigest()
else:
self.pwenc = ''
self.count = Counter(1)
self.openConnection()
def openConnection(self):
raise Exception('Abstract base class, use child class instead!')
def newRequest(self, name='GetPlantOverview', withPW=False, **params):
"""return a new rpc request structure (dictionary)"""
r = {'version': '1.0', 'proc': name, 'format': 'JSON'}
r['id'] = str(self.count())
if withPW:
r['passwd'] = self.pwenc
if params:
r['params'] = params
return r
def _rpc(self, *args):
raise Exception('Abstract base class, use child class instead!')
def printOverview(self):
"""print a short overview of the plant data"""
for v in self.getPlantOverview():
print("%15s (%15s): %s %s" %
(v['name'], v['meta'], v['value'], v['unit']))
# INDIGO UPDATE VARIABLES SECTION
# indigo.variables[1822257245] # "PV_EToday"
# indigo.variables[1469286291] # "PV_ETotal"
# indigo.variables[789149473] # "PV_Mode"
# indigo.variables[1958563501] # "PV_Pac"
# indigo.variables[532315452] # "PV_Overview"
if (v['meta'] == 'GriEgyTdy'):
indigo.variable.updateValue(1822257245, v['value'])
if (v['name'] == 'GriEgyTot'):
indigo.variable.updateValue(1469286291, v['value'])
#if (v['name'] == 'GriPwr'):
#indigo.variable.updateValue(1958563501, v['value'])
#if (v['name'] == 'Mode'):
#indigo.variable.updateValue(789149473, v['value'])
# wrapper methods for the RPC functions
def getPlantOverview(self):
res = self._rpc(self.newRequest('GetPlantOverview'))
return res['overview']
def getDevices(self):
res = self._rpc(self.newRequest('GetDevices'))
return res['devices']
def getProcessDataChannels(self, deviceKey):
res = self._rpc(self.newRequest('GetProcessDataChannels', device=deviceKey))
return res[deviceKey]
def getProcessData(self, channels):
res = self._rpc(self.newRequest('GetProcessData', devices=channels))
# reorder data structure: {devKey: {dict of channels}, ...}
# return {l['key']: l['channels'] for l in res['devices']}
r = {}
for l in res['devices']:
r[l['key']] = l['channels']
return r
def getParameterChannels(self, deviceKey):
res = self._rpc(self.newRequest('GetParameterChannels', withPW=True, device=deviceKey))
return res[deviceKey]
def getParameter(self, channels):
res = self._rpc(self.newRequest('GetParameter', withPW=True, devices=channels))
# reorder data structure: {devKey: {dict of channels}, ...}
# return {l['key']: l['channels'] for l in res['devices']}
r = {}
for l in res['devices']:
r[l['key']] = l['channels']
return r
def setParameter(self, *args):
raise Exception('Not yet implemented!')
class SunnyWebBoxHTTP(SunnyWebBoxBase):
"""Communication with a 'Sunny WebBox' via HTTP."""
def openConnection(self):
if py3:
from http.client import HTTPConnection
else:
from httplib import HTTPConnection
self.conn = HTTPConnection(self.host)
def _rpc(self, request):
"""send an rpc request as JSON object via http and read the result"""
js = json.dumps(request)
self.conn.request('POST', '/rpc', "RPC=%s" % js)
tmp = buf2str(self.conn.getresponse().read())
response = json.loads(tmp)
if response['id'] != request['id']:
raise Exception('RPC answer has wrong id!')
return response['result']
#class SunnyWebBoxUDPStream(SunnyWebBoxBase):
"""Communication with a 'Sunny WebBox' via UDP Stream."""
#def openConnection(self):
#from socket import socket, AF_INET, SOCK_DGRAM
#self.udpPort = 34268
#self.ssock = socket(AF_INET, SOCK_DGRAM)
#self.rsock = socket(AF_INET, SOCK_DGRAM)
#self.rsock.bind(("", self.udpPort))
#self.rsock.settimeout(100.0)
#def _rpc(self, request):
#"""send an rpc request as JSON object via UDP Stream and read the result"""
#js = ''.join(i+'\0' for i in json.dumps(request, separators=(',',':')))
#self.ssock.sendto(str2buf(js), (self.host, self.udpPort))
#while True:
#data, addr = self.rsock.recvfrom(10*1024)
#if addr[0] == self.host:
#break
#tmp = buf2str(data).replace('\0', '')
#response = json.loads(tmp)
#if response['id'] != request['id']:
#raise Exception('RPC answer has wrong id!')
#return response['result']
#if __name__ == '__main__':
#pw = ''
#ip = sys.argv[1]
#if len(sys.argv) > 2:
#pw = sys.argv[2]
ip = "192.168.0.98"
pw = "******"
swb = SunnyWebBoxHTTP(ip, password=pw)
# swb = SunnyWebBoxUDPStream(ip, password=pw)
# print('###### Overview:')
# swb.printOverview()
#
# for d in swb.getDevices():
# devKey = d['key']
# print("\n #### Device %s (%s):" % (devKey, d['name']))
#
# print("\n ## Process data:")
# channels = swb.getProcessDataChannels(devKey)
# data = swb.getProcessData([{'key':devKey, 'channels':channels}])
# for c in data[devKey]:
# print(" %15s (%15s): %s %s" %
# (c['name'], c['meta'], c['value'], c['unit']))
#
#
# print("\n ## Parameters:")
# channels = swb.getParameterChannels(devKey)
# data = swb.getParameter([{'key':devKey, 'channels':channels}])
# for c in data[devKey]:
# print(" %15s (%15s): %s %s" %
# (c['name'], c['meta'], c['value'], c['unit']))
indigo.server.log(unicode(swb))
jsonRequest = "SOME_JSON_FROM_DAVE"
swb = SunnyWebBoxHTTP(ip, password=pw)
jsonData = swb._rpc(jsonRequest)
def printOverview(self):
"""print a short overview of the plant data"""
for v in self.getPlantOverview():
print("%15s (%15s): %s %s" %
(v['name'], v['meta'], v['value'], v['unit']))
# INDIGO UPDATE VARIABLES SECTION
# indigo.variables[1822257245] # "PV_EToday"
# indigo.variables[1469286291] # "PV_ETotal"
# indigo.variables[789149473] # "PV_Mode"
# indigo.variables[1958563501] # "PV_Pac"
# indigo.variables[532315452] # "PV_Overview"
if (v['meta'] == 'GriEgyTdy'):
indigo.variable.updateValue(1822257245, v['value'])
if (v['name'] == 'GriEgyTot'):
indigo.variable.updateValue(1469286291, v['value'])
if (v['name'] == 'GriPwr'):
indigo.variable.updateValue(1958563501, v['value'])
if (v['name'] == 'Mode'):
indigo.variable.updateValue(789149473, v['value'])
# wrapper methods for the RPC functions
def getPlantOverview(self):
res = self._rpc(self.newRequest('GetPlantOverview'))
return res['overview']
def getDevices(self):
sma webbox poll
Script Error webbox_poll_2.py: unindent does not match any outer indentation level
Script Error around line 108 - "if (v['name'] == 'GriPwr'):"
Users browsing this forum: No registered users and 4 guests