-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlt232.py
217 lines (185 loc) · 8.63 KB
/
lt232.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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
############################################################################
# Copyright (C) 2023 by macGH #
# #
# This lib is free software; you can redistribute it and/or modify #
# it under the terms of the LGPL #
# This program is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# GNU General Public License for more details. #
# #
############################################################################
# Controlling the Lumetree devices LT 600 / 1000 / 2000
# Should also work for Trucki-Platine for Lumentree but not tested
# Should also work for TruckiRS485-Platine for SUN1000 but not tested
# and also not fully tested.
# Use at your own risk !
# Requirement for using
# Needed external python modules
# pip3 install minimalmodbus
# Version history
# macGH 26.11.2023 Version 0.1.0
# macGH 14.04.2024 Version 0.1.1: Added Trucki RS485 via UART
import os
import logging
import minimalmodbus
#API https://minimalmodbus.readthedocs.io/en/stable/apiminimalmodbus.html#apiminimalmodbus
#Lumentree modbus addresses, differ from documentation !
# 40 = Set Watt in decimal, no reading !
# 70 = AC Voltage *0,1
# 94 = Temperature *0,1
# 107 = Read Watt out *0,1
# 109 = DC Voltage *0,1
LT_Set_Watt = 40
LT_AC_Voltage = 70
LT_Temperature = 94
LT_Read_Watt = 107
LT_DC_Voltage = 109
#[0] Set inverter AC output power [W*10] (Update rate ~100ms)
#[1] Read display AC output power [W*10] (Update rate ~1.3s)
#[2] Read display grid voltage [V*10] (Update rate ~1.3s)
#[3] Read display battery [V*10] (Update rate ~1.3s)
#[4] Set / Read DAC Value; [0]=0! (Update rate ~100ms)
#[5] =1 Start Calibration. 17 Steps (10s per step)
#[6] Mirror of REG[0] [W*10] (Update rate ~100ms) Firmware >= 1.06
#[7] Temperature [0..118°C] (Update rate ~100ms) Firmware >= 1.06
TR_Set_Watt = 0
TR_AC_Voltage = 2
TR_Temperature = 7
TR_Read_Watt = 1
TR_DC_Voltage = 3
######################################################################################
# Explanations
######################################################################################
######################################################################################
# def __init__(self, devtype, devpath, idadr, loglevel):
#
# devtype
# 0 = Lumentree
# 1 = Trucki RS485 PCB (https://github.com/trucki-eu/RS485-Interface-for-Sun-GTIL2-1000)
#
# devpath
# Add the /dev/tty device here, mostly .../dev/ttyUSB0, if empty default path /dev/ttyUSB0 is used
#
# idadr
# ID of the lumentree/TruckiRS485 if you have more than one installed, if empty 1 is used
#
# loglevel
# Enter Loglevel 0,10,20,30,40,50
# CRITICAL 50
# ERROR 40
# WARNING 30
# INFO 20
# DEBUG 10
# NOTSET 0
######################################################################################
#########################################
##class
class lt232:
def __init__(self, devtype, devpath, idadr, loglevel):
#init with default
self.devtype = devtype
self.devpath = "/dev/ttyUSB0" #just try if is is the common devpath
self.idadr = 1 #just try if is is the common idadr
self.loglevel = 20 #just use info as default
if devpath != "": self.devpath = devpath
if idadr != "": self.idadr = idadr
if loglevel != "": self.loglevel = loglevel
if(devtype == 0): #Lumentree
self.DEV_Set_Watt = 40
self.DEV_AC_Voltage = 70
self.DEV_Temperature = 94
self.DEV_Read_Watt = 107
self.DEV_DC_Voltage = 109
if(devtype == 1): #Trucki RS485
self.DEV_Set_Watt = 0
self.DEV_AC_Voltage = 2
self.DEV_Temperature = 7
self.DEV_Read_Watt = 1
self.DEV_DC_Voltage = 3
logging.basicConfig(level=loglevel, encoding='utf-8')
logging.info("Init lt232 class")
def lt232_open(self):
logging.info("open serial interface")
try:
self.lt232 = minimalmodbus.Instrument(self.devpath, self.idadr, 'rtu', False, (self.loglevel < 20)) # port name, slave address (in decimal), Mode, close_port_after_each_call, debug
except Exception as e:
logging.error("Can not init Lumentree/TruckiRS485 device: " + self.devpath + " address: " + self.idadr)
logging.error("If device is correct, check if User is in dialout group !")
raise Exception("LUMENTREE/TRUCKIRS485 DEVICE NOT FOUND")
self.lt232.serial.baudrate = 9600 # Baudrate
self.lt232.serial.timeout = 0.9 # according Spec LT has a 1 Second timeout
self.lt232.serial.write_timeout = 0.9 # according Spec LT has a 1 Second timeout
#Can work in some environment better
#self.lt232.serial.exclusive = True
#This Should be all default already
#self.lt232.clear_buffers_before_each_transaction = True
#self.lt232.serial.bytesize = 8
#self.lt232.serial.parity = minimalmodbus.serial.PARITY_NONE
#self.lt232.serial.stopbits = 1
logging.debug(self.lt232)
def lt232_close(self):
logging.info("close serial interface")
try:
self.lt232.serial.close() #Shutdown our interface
except Exception as e:
logging.error("Can not close Lumentree/TruckiRs485 device")
raise Exception("LUMENTREE/TRUCKIRS485 DEVICE CAN NOT BE CLOSED")
#############################################################################
# Read Write operation function
def lt232_IO(self, regnr, wr, value):
#Lumentree modbus addresses, differ from documentation !
# 40 = Set Watt in decimal, no reading ! Read see 107
# 70 = AC Voltage *0,1
# 94 = Temperature *0,1
# 107 = Read Watt out *0,1
# 109 = DC Voltage *0,1
logging.debug("lt232_IO: " + str(regnr) + "-" + str(wr) + "-" + str(value))
if wr == 0: #read
try:
readvalue = self.lt232.read_register(regnr, 0, 3, False) # Registernumber (number of decimals)
except Exception as e:
logging.error("Exception during read operation !")
raise Exception(str(e))
return -1
return readvalue
if wr == 1: #write
#SUN: 0 = Set output in Watt
#LT : 40 = Set output in Watt
try:
self.lt232.write_register(regnr, value, 0, 16, False) # Registernumber, value, number of decimals for storage
except Exception as e:
logging.error("Exception during write operation !")
raise Exception(str(e))
return -1
return value
#############################################################################
# Operation function
def set_watt_out(self,val):
logging.debug("write power out: " + str(val))
if(self.devtype == 1): #Trucki RS485 for SUN
val = val*10
self.lt232_IO(self.DEV_Set_Watt,1,val) #does only return 0
return val #return the same value to signal OK
def readACvoltage(self):
logging.debug("read AC voltage of lumentree/TruckiRS485")
rval = self.lt232_IO(self.DEV_AC_Voltage,0,0)
logging.debug("AC voltage of lumentree/TruckiRS485: " + str(rval/10))
return (rval/10)
def readtemp(self):
logging.debug("read temperature of lumentree/TruckiRS485")
rval = self.lt232_IO(self.DEV_Temperature,0,0)
logging.debug("Lumentree/TruckiRS485 temperature: " + str(rval/10))
return (rval/10)
def read_watt_out(self):
logging.debug("read power out")
rval = self.lt232_IO(self.DEV_Read_Watt,0,0)
rvali = int(rval/10) #return without decimals
if(rvali < 10): rvali = 0 #check if lumentree/TruckiRS485 is off <15 = off
return int(rvali)
def readDCvoltage(self):
logging.debug("read AC voltage of lumentree/TruckiRS485")
rval = self.lt232_IO(self.DEV_DC_Voltage,0,0)
logging.debug("DC voltage of lumentree/TruckiRS485: " + str(rval))
#return without /10 to have the decimals
return int(rval)