rasolar/logger.py

239 lines
8.4 KiB
Python
Executable File

#!/usr/bin/env python
import numpy as np
import os, serial,time,socket,sys,json,smbus2,bme280,logging,requests,getopt
# import the server implementation
from pymodbus.client.sync import ModbusSerialClient as ModbusClient
# import ADC
from Adafruit_ADS1x15 import ADS1115
import vedirect
import upload_osm
configfile="config.json"
a = 2
# push options to internet
push_count=20 # wait 5 cycles till upload to opensensemap
push_counter=0
push_vars=["temperature","humidity","pressure"]
push_data={}
push_mean_counts={}
for i in push_vars:
push_data[i]=0
push_mean_counts[i]=0
sensebox_id='5cf60a0907460b001b8881fd' # id of opensensemap
sensebox_sid={}
sensebox_sid['temperature']='5cf60a0907460b001b888200' # id for temperaturemeasurement
sensebox_sid['humidity']='5cf60a0907460b001b8881ff' # id for humidity measurement
sensebox_sid['pressure']='5cf60a0907460b001b8881fe' # id for pressure measurement
luftdaten_id=56009074600018881
# host and port of internal logging server
HOST, PORT = "banana", 24048
# config of bme280 sensor
bme_port=1
bme_add=0x77
bbme=True
try:
bme_bus=smbus2.SMBus(bme_port)
except:
bbme=False
else:
calibration_params=bme280.load_calibration_params(bme_bus,bme_add)
# configure the client logging
logging.basicConfig()
log = logging.getLogger('./modbus.error')
log.setLevel(logging.ERROR)
# choose the serial client
btristar=True
try:
client = ModbusClient(method='rtu', port='/dev/ttyUSB0', baudrate=9600, timeout=1)
except:
btristar=False
else:
client.connect()
# declare ve mppt
bve=False
try:
ve=vedirect('/dev/serial/by-id/usb-VictronEnergy_BV_VE_Direct_cable_VE1SSBVT-if00-port0',60)
except:
bve=False
# declare adc
badc1=True
badc2=True
try:
adc = ADS1115()
except:
badc1=False
try:
adcc = ADS1115(address=0x49, busnum=1)
except:
badc2=False
GAIN = 1
# declare vars
channel_names=["time","CPU_temp","a0_0","a0_1","a0_2","a0_3","a1_0","a1_1","a1_2","a1_3","volt_scale","amp_scale",
"volt_bat_term","volt_bat_sens","volt_arr","amp_bat","amp_arr","temp_heatsink","temp_bat","ah_res",
"ah_tot","kwh_res","kwh_tot","watt_in","watt_out","hour_tot","state","volt_sweep_mp","volt_sweep_oc",
"temperature","pressure","humidity","volt_bat_ve","volt_arr_ve","amp_ve","watt_ve","days_ve"]
ch_val=np.zeros(len(channel_names))
for i in range(len(channel_names)):
ch_val[i]=(-1)
ch_old=ch_val
while a > 1:
# copy channel values to backup
ch_old=ch_val.copy()
# set actual time
timestamp=int(1000*time.time())
ch_val[channel_names.index("time")]=timestamp
# get cpu temperature
tempC=0
tFile = open('/sys/class/thermal/thermal_zone0/temp')
ch_val[channel_names.index("CPU_temp")] = float(tFile.read())
tFile.close()
# read adc's
if badc1 or badc2:
for i in range(4):
if badc1:
ch_val[channel_names.index("a0_{0}".format(i))]=adc.read_adc(i,gain=GAIN)
if badc2:
ch_val[channel_names.index("a1_{0}".format(i))]=adcc.read_adc(i,gain=GAIN)
if btristar:
#read the registers from logical address 0 to 30.
try:
rr = client.read_holding_registers(0,90,unit=1)
except:
print("could not get data from tristar")
else:
#scaling
ch_val[channel_names.index("volt_scale")]=rr.registers[0]*65536+rr.registers[1]
ch_val[channel_names.index("amp_scale")]= rr.registers[2]*65536+rr.registers[3]
#the stuff we want
ch_val[channel_names.index("volt_bat_term")]=rr.registers[25]
ch_val[channel_names.index("volt_bat_sens")]=rr.registers[26]
ch_val[channel_names.index("volt_arr")]=rr.registers[27] # Array voltage
ch_val[channel_names.index("amp_bat")]=rr.registers[28] # Battery current
ch_val[channel_names.index("amp_arr")]=rr.registers[29] # Array current
ch_val[channel_names.index("temp_heatsink")]=rr.registers[35] # Temperature heatsink
ch_val[channel_names.index("temp_bat")]=rr.registers[36] # Temperature battery
ch_val[channel_names.index("ah_res")]=rr.registers[52] * 65536 + rr.registers[53] # Ah resetable
ch_val[channel_names.index("ah_tot")]=rr.registers[54] * 65536 + rr.registers[55] # Ah total
ch_val[channel_names.index("kwh_res")]=rr.registers[56] # kwh resetable
ch_val[channel_names.index("kwh_tot")]=rr.registers[57] # kwh total
ch_val[channel_names.index("watt_in")]=rr.registers[58] # Power in
ch_val[channel_names.index("watt_out")]=rr.registers[59] # Power out
ch_val[channel_names.index("hour_tot")]=rr.registers[42] * 65536 + rr.registers[43] # hour total
ch_val[channel_names.index("state")]=rr.registers[50] # State
ch_val[channel_names.index("volt_sweep_mp")]=rr.registers[61] # Array voltage
ch_val[channel_names.index("volt_sweep_oc")]=rr.registers[62] # Array voltage
# read bme280 (temperature, humidity, pressure)
if bbme:
bme_data=bme280.sample(bme_bus,bme_add,calibration_params)
ch_val[channel_names.index("temperature")]=int(1000*bme_data.temperature) # Temperature
ch_val[channel_names.index("pressure")]=int(1000*bme_data.pressure) # Pressure
ch_val[channel_names.index("humidity")]=int(1000*bme_data.humidity) # Humidity
# read ve data
if bve:
try:
vedata=ve.read_data_single()
except:
print("could not read VE")
else:
ch_val[channel_names.index("volt_bat_ve")]=int(vedata['V']) # Battery voltage measured by ve
ch_val[channel_names.index("volt_arr_ve")]=int(vedata['VPV']) # Array voltage measured by ve
ch_val[channel_names.index("amp_ve")]=int(vedata['I']) # loading current by ve
ch_val[channel_names.index("watt_ve")]=int(vedata['PPV']) # Array power measured by ve
ch_val[channel_names.index("days_ve")]=int(vedata['HSDS']) # total days online ve
timefile=round(timestamp/3600000)
f1=open("/home/pi/log/data_{:d}.txt".format(int(timefile)),"a")
payload={}
for i in range(len(ch_val)):
if ch_val[i] != ch_old[i]:
f1.write(channel_names[i] + ":{0};".format(int(ch_val[i])))
if channel_names[i] != "time":
payload[channel_names[i]]=int(ch_val[i])
if channel_names[i] in push_vars:
if push_counter == push_count:
sense_data=push_data[channel_names[i]]/(1000*push_mean_counts[channel_names[i]])
upload_osm(sensebox_sid[channel_names[i]],round(sense_data,2))
push_data[channel_names[i]]=0
push_mean_counts[channel_names[i]]=0
else:
push_data[channel_names[i]]=push_data[channel_names[i]]+ch_val[i]
push_mean_counts[channel_names[i]]=push_mean_counts[channel_names[i]]+1
f1.write("\n")
f1.close()
json_out={"time": ch_val[channel_names.index("time")],"device": "rasolar","payload":payload}
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
except:
print("{}: could not connect to database".format(time.time()))
else:
s.connect((HOST, PORT))
s.sendall(json.dumps(json_out))
s.close()
# volt_batt=rr.registers[24] * volt_scaling / 65536 / 32768
# volt_batt_t=rr.registers[25] * volt_scaling / 65536 / 32768
# volt_batt_sens=rr.registers[26] * volt_scaling / 65536 / 32768
# volt_arr=rr.registers[27] * volt_scaling / 65536 / 32768
# curr_batt=rr.registers[28] * amp_scaling / 65536 / 32768
# curr_arr=rr.registers[29] * amp_scaling / 65536 / 32768
# temp_heatsink=rr.registers[35]
# temp_batt=rr.registers[36]
# ah_reset = rr.registers[52] * 65536 + rr.registers[53]
# ah_total = rr.registers[54] * 65536 + rr.registers[55]
# kwh_reset = rr.registers[56]
# kwh_total = rr.registers[57]
# power_in = rr.registers[58] * volt_scaling * amp_scaling / 131072 / 65536 / 65536
# power_out = rr.registers[59] * volt_scaling * amp_scaling / 131072 / 65536 / 65536
# hourm = rr.registers[42]*65536+rr.registers[43]
# charge_state = rr.registers[50]
#debug
# print "Battery Voltage: %.2f" % volt_batt
# print "Battery Voltage_t: %.2f" % volt_batt_t
# print "Battery Voltage Sense: %.2f" % volt_batt_sens
# print "Array Voltage: %.2f" % volt_arr
# print "Battery Current: %.2f" % curr_batt
# print "Array Current: %.2f" % curr_arr
# print "Power in: %.2f" % power_in
# print "Power out: %.2f" % power_out
# print "Controller Temp: %.2f" % temp_heatsink
# print "Battery Temp: %.2f" % temp_batt
# print "AH total: %.2f" % ah_total
# print "kWh total: %.2f" % kwh_total
# print "hours: %.2f" % hourm
# print "charge state : %.2f" % charge_state
if push_counter>=push_count:
push_counter = 1
else:
push_counter=push_counter+1
time.sleep(5)
# close the client
client.close()
f1.close()
print("done")