forked from salberin/Solaredge-influxdb
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsolaredge.py
126 lines (112 loc) · 5.83 KB
/
solaredge.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import argparse
import datetime
import logging
from aiohttp import ClientConnectionError
from pyModbusTCP.client import ModbusClient
from pymodbus.constants import Endian
from pymodbus.payload import BinaryPayloadDecoder
import asyncio
from aioinflux import InfluxDBClient, InfluxDBWriteError
datapoint = {
'measurement': 'SolarEdge',
'tags': {
'inverter': '1'
},
'fields': {}
}
logger = logging.getLogger('solaredge')
async def write_to_influx(dbhost, dbport, dbname='solaredge'):
global client
def trunc_float(floatval):
return float('%.2f' % floatval)
try:
solar_client = InfluxDBClient(host=dbhost, port=dbport, db=dbname)
await solar_client.create_database(db=dbname)
except ClientConnectionError as e:
logger.error(f'Error during connection to InfluxDb {dbhost}: {e}')
return
logger.info('Database opened and initialized')
while True:
try:
reg_block = client.read_holding_registers(40069, 38)
if reg_block:
# print(reg_block)
data = BinaryPayloadDecoder.fromRegisters(reg_block, byteorder=Endian.Big, wordorder=Endian.Big)
data.skip_bytes(12)
scalefactor = 10**data.decode_16bit_int()
data.skip_bytes(-10)
# Register 40072-40075
datapoint['fields']['AC Total Current'] = trunc_float(data.decode_16bit_uint() * scalefactor)
datapoint['fields']['AC Current phase A'] = trunc_float(data.decode_16bit_uint() * scalefactor)
datapoint['fields']['AC Current phase B'] = trunc_float(data.decode_16bit_uint() * scalefactor)
datapoint['fields']['AC Current phase C'] = trunc_float(data.decode_16bit_uint() * scalefactor)
data.skip_bytes(14)
scalefactor = 10**data.decode_16bit_int()
data.skip_bytes(-8)
# register 40080-40082
datapoint['fields']['AC Voltage phase A'] = trunc_float(data.decode_16bit_uint() * scalefactor)
datapoint['fields']['AC Voltage phase B'] = trunc_float(data.decode_16bit_uint() * scalefactor)
datapoint['fields']['AC Voltage phase C'] = trunc_float(data.decode_16bit_uint() * scalefactor)
data.skip_bytes(4)
scalefactor = 10**data.decode_16bit_int()
data.skip_bytes(-4)
# register 40084
datapoint['fields']['AC Power output'] = trunc_float(data.decode_16bit_int() * scalefactor)
data.skip_bytes(24)
scalefactor = 10**data.decode_16bit_int()
data.skip_bytes(-6)
# register 40094
datapoint['fields']['AC Lifetimeproduction'] = trunc_float(data.decode_32bit_uint() * scalefactor)
data.skip_bytes(2)
scalefactor = 10**data.decode_16bit_int()
data.skip_bytes(-2)
# register 40097
datapoint['fields']['DC Current'] = trunc_float(data.decode_16bit_uint() *scalefactor)
data.skip_bytes(4)
scalefactor = 10**data.decode_16bit_int()
data.skip_bytes(-4)
# register 40099
datapoint['fields']['DC Voltage'] = trunc_float(data.decode_16bit_uint() * scalefactor)
data.skip_bytes(4)
scalefactor = 10**data.decode_16bit_int()
data.skip_bytes(-4)
# datapoint 40101
datapoint['fields']['DC Power input'] = trunc_float(data.decode_16bit_int() * scalefactor)
datapoint['time'] = str(datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc).isoformat())
logger.debug(f'Writing to Influx: {str(datapoint)}')
await solar_client.write(datapoint)
else:
# Error during data receive
if client.last_error() == 2:
logger.error(f'Failed to connect to SolarEdge inverter {client.host()}!')
elif client.last_error() == 3 or client.last_error() == 4:
logger.error('Send or receive error!')
elif client.last_error() == 5:
logger.error('Timeout during send or receive operation!')
except InfluxDBWriteError as e:
logger.error(f'Failed to write to InfluxDb: {e}')
except IOError as e:
logger.error(f'I/O exception during operation: {e}')
except Exception as e:
logger.error(f'Unhandled exception: {e}')
await asyncio.sleep(5)
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('--influxdb', default='localhost')
parser.add_argument('--influxport', type=int, default=8086)
parser.add_argument('--port', type=int, default=502, help='ModBus TCP port number to use')
parser.add_argument('--unitid', type=int, default=1, help='ModBus unit id to use in communication')
parser.add_argument('solaredge', metavar='SolarEdge IP', help='IP address of the SolarEdge inverter to monitor')
parser.add_argument('--debug', '-d', action='count')
args = parser.parse_args()
logging.basicConfig()
if args.debug and args.debug >= 1:
logging.getLogger('solaredge').setLevel(logging.DEBUG)
if args.debug and args.debug == 2:
logging.getLogger('aioinflux').setLevel(logging.DEBUG)
print('Starting up solaredge monitoring')
print(f'Connecting to Solaredge inverter {args.solaredge} on port {args.port} using unitid {args.unitid}')
print(f'Writing data to influxDb {args.influxdb} on port {args.influxport}')
client = ModbusClient(args.solaredge, port=args.port, unit_id=args.unitid, auto_open=True)
logger.debug('Running eventloop')
asyncio.get_event_loop().run_until_complete(write_to_influx(args.influxdb, args.influxport))