123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537 |
- #!/usr/bin/env python
- import numpy as np
- import os, serial,time,socket,sys,json,logging,requests,getopt
- # import the server implementation
- # import ADC
- #import vedirect
- #import upload_osm
- configfile="config.json"
- cf=open(configfile,"r")
- log_conf=json.load(cf)
- cf.close()
- devicename=socket.gethostname()
- if "device" in log_conf:
- devicename=log_conf['device']
- mean_count=5
- if "mean_count" in log_conf:
- mean_count=int(log_conf['mean_count'])
- channel_names=["time","CPU_temp"]
- channel_info={"time":{"sensor":"CPU","timestamp":0,"i2c":0},"CPU_temp":{"sensor":"CPU","timestamp":0,"i2c":0}}
- a = 2
- # import vedirect from https://github.com/karioja/vedirect
- # description of channels:https://beta.ivc.no/wiki/index.php/Victron_VE_Direct_DIY_Cable
- class vedirect:
- def __init__(self, serialport, timeout):
- self.serialport = serialport
- self.ser = serial.Serial(serialport, 19200, timeout=timeout)
- self.header1 = '\r'
- self.header2 = '\n'
- self.hexmarker = ':'
- self.delimiter = '\t'
- self.key = ''
- self.value = ''
- self.bytes_sum = 0;
- self.state = self.WAIT_HEADER
- self.dict = {}
- (HEX, WAIT_HEADER, IN_KEY, IN_VALUE, IN_CHECKSUM) = range(5)
- def input(self, byte):
- if byte == self.hexmarker and self.state != self.IN_CHECKSUM:
- self.state = self.HEX
- if self.state == self.WAIT_HEADER:
- self.bytes_sum += ord(byte)
- if byte == self.header1:
- self.state = self.WAIT_HEADER
- elif byte == self.header2:
- self.state = self.IN_KEY
- return None
- elif self.state == self.IN_KEY:
- self.bytes_sum += ord(byte)
- if byte == self.delimiter:
- if (self.key == 'Checksum'):
- self.state = self.IN_CHECKSUM
- else:
- self.state = self.IN_VALUE
- else:
- self.key += byte
- return None
- elif self.state == self.IN_VALUE:
- self.bytes_sum += ord(byte)
- if byte == self.header1:
- self.state = self.WAIT_HEADER
- self.dict[self.key] = self.value;
- self.key = '';
- self.value = '';
- else:
- self.value += byte
- return None
- elif self.state == self.IN_CHECKSUM:
- self.bytes_sum += ord(byte)
- self.key = ''
- self.value = ''
- self.state = self.WAIT_HEADER
- if (self.bytes_sum % 256 == 0):
- self.bytes_sum = 0
- return self.dict
- else:
- print 'Malformed packet'
- self.bytes_sum = 0
- elif self.state == self.HEX:
- self.bytes_sum = 0
- if byte == self.header2:
- self.state = self.WAIT_HEADER
- else:
- raise AssertionError()
- def read_data(self):
- while True:
- byte = self.ser.read(1)
- packet = self.input(byte)
- def read_data_single(self):
- while True:
- byte = self.ser.read(1)
- packet = self.input(byte)
- if (packet != None):
- return packet
- def read_data_callback(self, callbackFunction):
- while True:
- byte = self.ser.read(1)
- if byte:
- packet = self.input(byte)
- if (packet != None):
- callbackFunction(packet)
- else:
- break
- def print_data_callback(data):
- print data
- # end import vedirect
- def upload_osm(sensebox_id,sensor_id,value):
- url="https://ingress.opensensemap.org/boxes/%s/%s" % (sensebox_id,sensor_id)
- r = requests.post(url,json={'value': value})
- if (r.status_code != requests.codes.ok) & (r.status_code != 201):
- print("Error %d: %s" % (r.status_code,r.text))
- # host and port of internal logging server
- bsql=False
- if "sqlserver" in log_conf:
- bsql=True
- if "enable" in log_conf['sqlserver']:
- if log_conf['sqlserver']['enable'] == 0:
- bsql=False
- if bsql:
- sqlhost=log_conf['sqlserver']['host']
- sqlport=log_conf['sqlserver']['port']
- # config of lux sensor tls2591
- btls=False
- if "tsl2591" in log_conf:
- btls=True
- if "enable" in log_conf['tsl2591']:
- if log_conf['tsl2591']['enable'] == 0:
- btls=False
- if btls:
- import tsl2591
- tsl_port=1
- if "port" in log_conf['tsl2591']:
- tsl_port=int(log_conf['tsl2591']['port'])
- tsl_add=0x29
- if "address" in log_conf['tsl2591']:
- tsl_add=int(log_conf['tsl2591']['address'],16)
- try:
- tsl = tsl2591.Tsl2591(i2c_bus=tsl_port,sensor_address=tsl_add) # initialize
- except:
- btls=False
- else:
- channel_names.append("lux")
- channel_info["lux"]={"sensor":"tsl2591","timestamp":0,"i2c":tsl_add}
- # config of lux sensor tls2591
- bveml=False
- if "veml6070" in log_conf:
- bveml=True
- if "enable" in log_conf['veml6070']:
- if log_conf['veml6070']['enable'] == 0:
- bveml=False
- if bveml:
- import veml6070
- veml_port=1
- if "port" in log_conf['veml6070']:
- veml_port=int(log_conf['veml6070']['port'])
- try:
- veml = veml6070.Veml6070(i2c_bus=veml_port)
- except:
- bveml=False
- else:
- channel_names.append("uv")
- channel_info["uv"]={"sensor":"veml6070","timestamp":0,"i2c":0x38}
- # config of bme280 sensor
- # use pip install RPi.bme280 for library
- bbme=False
- if "bme280" in log_conf:
- bbme=True
- if "enable" in log_conf['bme280']:
- if log_conf['bme280']['enable'] == 0:
- bbme=False
- if bbme:
- import smbus2
- import bme280
- if "port" in log_conf['bme280']:
- bme_port=log_conf['bme280']['port']
- else:
- bme_port=1
- if "address" in log_conf['bme280']:
- bme_add=int(log_conf['bme280']['address'],16)
- else:
- bme_add=0x77
- try:
- bme_bus=smbus2.SMBus(bme_port)
- except:
- bbme=False
- else:
- calibration_params=bme280.load_calibration_params(bme_bus,bme_add)
- for n in ("temperature","humidity","pressure"):
- channel_names.append(n)
- channel_info[n]={"sensor":"bme280","timestamp":0,"i2c":bme_add}
- # configure the client logging
- logging.basicConfig()
- log = logging.getLogger('./modbus.error')
- log.setLevel(logging.ERROR)
- # configure tristar
- btristar=False
- if "tristar" in log_conf:
- btristar=True
- if "enable" in log_conf['tristar']:
- if log_conf['tristar']['enable'] == 0:
- btristar=False
- if btristar:
- import smbus
- from pymodbus.client.sync import ModbusSerialClient as ModbusClient
- tri_port='/dev/ttyUSB0'
- if "port" in log_conf['tristar']:
- tri_port=log_conf['tristar']['port']
- tri_baud=9600
- if "baud" in log_conf['tristar']:
- tri_baud=log_conf['tristar']['baud']
- tri_timeout=1
- if "timeout" in log_conf['tristar']:
- tri_timeout=log_conf['tristar']['timeout']
- try:
- triclient = ModbusClient(method='rtu', port=tri_port, baudrate=tri_baud, timeout=tri_timeout)
- except:
- btristar=False
- else:
- triclient.connect()
- for i in ["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"]:
- channel_names.append(i)
- channel_info[i]={"sensor":"tristar","timestamp":0,"i2c":0}
-
- # declare ve mppt
- bve=False
- if "vedirect" in log_conf:
- bve=True
- if "enable" in log_conf['vedirect']:
- if log_conf['vedirect']['enable'] == 0:
- bve=False
- if "port" in log_conf['vedirect']:
- bve_port=log_conf['vedirect']['port']
- else:
- bve_port='/dev/serial/by-id/usb-VictronEnergy_BV_VE_Direct_cable_VE1SSBVT-if00-port0'
- print(bve_port)
- try:
- ve=vedirect(bve_port,60)
- except:
- bve=False
- else:
- for i in ["volt_bat_ve","volt_arr_ve","amp_ve","watt_ve","days_ve"]:
- channel_names.append(i)
- channel_info[i]={"sensor":"victron","timestamp":0,"i2c":0}
- print(bve)
- # declare adc
- badc=False
- if "ads1x15" in log_conf:
- badc=True
- ads_conf=log_conf['ads1x15']
- if "enable" in ads_conf:
- if ads_conf['enable'] == 0:
- badc=False
- if badc:
- adc={}
- GAIN=1
- if "gain" in ads_conf:
- GAIN=ads_conf['gain']
- if "adc" in ads_conf:
- from Adafruit_ADS1x15 import ADS1115
- from Adafruit_ADS1x15 import ADS1015
- adc_count=0
- tadc=ads_conf['adc']
- for x in tadc:
- y=tadc[x]
- adc_address=0x48
- if "address" in y:
- adc_address=int(y['address'],16)
- abc_bus=1
- if "busnum" in y:
- adc_bus=y['busnum']
- adc_type=1015
- if "type" in y:
- adc_type=y['type']
- adc_assigned=False
- if adc_type == 1115:
- try:
- adc[adc_count]=ADS1115(address=adc_address,busnum=adc_bus)
- adc_assigned=True
- except:
- print("could not assign ADC")
- if adc_type == 1015:
- try:
- adc[adc_count]=ADS1015(address=adc_address,busnum=adc_bus)
- adc_assigned=True
- except:
- print("could not assign ADC")
- if adc_assigned:
- for j in range(4):
- cnadc="a"+str(adc_count)+"_"+str(j)
- channel_names.append(cnadc)
- channel_info[cnadc]={"sensor":"ads"+str(adc_type),"timestamp":0,"i2c":adc_address}
- adc_count=adc_count+1
- else:
- badc=False
- bmcp9808=False
- if "mcp9808" in log_conf:
- bmcp9808=True
- if "enable" in log_conf['mcp9808']:
- if log_conf['mcp9808']['enable'] == 0:
- bmcp9808=False
- if bmcp9808:
- import Adafruit_MCP9808.MCP9808 as MCP9808
- try:
- sens_9808 = MCP9808.MCP9808()
- except:
- bmcp9808 = False
- else:
- sens_9808.begin()
- channel_names.append("temp_9808")
- channel_info["temp_9808"]={"sensor":"bmcp9808","timestamp":0,"i2c":0x18}
- # push options to internet
- bosm=False
- if "opensensemap" in log_conf:
- bosm=True
- conf_osm=log_conf['opensensemap']
- if "enable" in conf_osm:
- if conf_osm['enable'] == 0:
- bosm = False
- if bosm:
- try:
- push_count=conf_osm['push_count']
- except:
- push_count=20 # wait 5 cycles till upload to opensensemap
- push_counter=0
- sensebox_id=conf_osm['sensebox_id'] # id of opensensemap
- push_vars=conf_osm['sensors'].keys()
- for pv in conf_osm['sensors'].keys():
- if (pv not in channel_names):
- if len(push_vars)>1:
- push_vars.remove(pv)
- else:
- push_vars=[]
- if (len(push_vars) == 0):
- bosm=False
- else:
- push_data={}
- push_mean_counts={}
- sensebox_sid={}
- for i in push_vars:
- push_data[i]=0
- push_mean_counts[i]=0
- sensebox_sid[i]=conf_osm['sensors'][i]
- #luftdaten_id=56009074600018881
- ch_val=np.zeros(len(channel_names))
- for i in range(len(channel_names)):
- ch_val[i]=(-1)
- while a > 1:
- # copy channel values to backup
- ch_old=ch_val.copy()
-
- ch_val=np.zeros(len(channel_names))
- ch_mean=ch_val.copy()
-
- # set actual time
- timestamp=int(1000*time.time())
- ch_val[channel_names.index("time")]=timestamp
-
- for n in range(mean_count):
- # get cpu temperature
- ch_val[channel_names.index("CPU_temp")] = int(open('/sys/class/thermal/thermal_zone0/temp').read())
-
- # get mcp9808 temperatur
- if bmcp9808:
- ch_val[channel_names.index("temp_9808")] = int(1000*sens_9808.readTempC())
- # get tls lux
- if btls:
- tsl_full,tsl_ir=tsl.get_full_luminosity()
- ch_val[channel_names.index("lux")] = int(1000*tsl.calculate_lux(tsl_full,tsl_ir))
- # get uv index
- if bveml:
- tsl_full,tsl_ir=tsl.get_full_luminosity()
- veml.set_integration_time(veml6070.INTEGRATIONTIME_1T)
- # uv_raw = veml.get_uva_light_intensity_raw()
- ch_val[channel_names.index("uv")] = int(1000*veml.get_uva_light_intensity())
- # read adc's
- if badc:
- for i in adc:
- cname="a"+str(i)+"_{0}"
- for j in range(4):
- ch_val[channel_names.index(cname.format(j))]=adc[i].read_adc(j,gain=GAIN)
-
- if btristar:
- try:
- rr = triclient.read_holding_registers(0,90,unit=1)
- except:
- print("could not get data from tristar")
- else:
- try:
- ch_val[channel_names.index("volt_scale")]=rr.registers[0]*65536+rr.registers[1]
- except:
- print("could not read from tristar")
- else:
- ch_val[channel_names.index("amp_scale")]= rr.registers[2]*65536+rr.registers[3]
- 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:
- if 'V' in vedata:
- ch_val[channel_names.index("volt_bat_ve")]=int(vedata['V']) # Battery voltage measured by ve
- if 'VPV' in vedata:
- ch_val[channel_names.index("volt_arr_ve")]=int(vedata['VPV']) # Array voltage measured by ve
- if 'I' in vedata:
- ch_val[channel_names.index("amp_ve")]=int(vedata['I']) # loading current by ve
- if 'PPV' in vedata:
- ch_val[channel_names.index("watt_ve")]=int(vedata['PPV']) # Array power measured by ve
- if 'HSDS' in vedata:
- ch_val[channel_names.index("days_ve")]=int(vedata['HSDS']) # total days online ve
- for i in range(len(ch_val)):
- ch_mean[i]=ch_mean[i]+ch_val[i]
-
- for i in range(len(ch_val)):
- ch_val[i]=int(ch_mean[i]/mean_count)
-
- timefile=round(timestamp/3600000)
- f1=open("/home/pi/log/data_{:d}.txt".format(int(timefile)),"a")
- payload={}
- for i in range(len(ch_val)):
- cni=channel_names[i]
- if ch_val[i] != ch_old[i]:
- f1.write(cni + ":{0};".format(int(ch_val[i])))
- if cni != "time":
- payload[cni]=channel_info[cni]
- payload[cni]['value']=int(ch_val[i])
- channel_info[cni]['timestamp']=timestamp
- f1.write("\n")
- f1.close()
- if bosm:
- for pv in push_vars:
- if push_mean_counts[pv] == push_count:
- sense_data=push_data[pv]/(1000*push_mean_counts[pv])
- if pv == "volt_sweep_oc":
- sense_data=sense_data * ch_val[channel_names.index("volt_scale")] / 65536 / 32768
- upload_osm(sensebox_id,sensebox_sid[pv],round(sense_data,2))
- push_data[pv] = 0
- push_mean_counts[pv] = 0
- else:
- if channel_info[pv]['timestamp'] == timestamp:
- push_data[pv]=push_data[pv]+ch_val[channel_names.index(pv)]
- push_mean_counts[pv]=push_mean_counts[pv]+1
- if bsql:
- json_out={"time": ch_val[channel_names.index("time")],"device": devicename,"payload":payload}
- try:
- s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- except:
- print("{}: could not connect to database".format(time.time()))
- else:
- try:
- s.connect((sqlhost, sqlport))
- except:
- print("{}: could not connect to database".format(time.time()))
- else:
- 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]
- if bosm:
- 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")
|