def discover_devices(device_node, modbus_address, conn_type, baud, port, debug): try: if conn_type == 'tcp': port_int = int(port) sunspec_client = sp_client.SunSpecClientDevice(sp_client.TCP, modbus_address, ipaddr=device_node, ipport=port_int, timeout=TIMEOUT_VAL) elif conn_type == 'rtu': sunspec_client = sp_client.SunSpecClientDevice(sp_client.RTU, modbus_address, name=device_node, baudrate=baud, timeout=TIMEOUT_VAL) # read all models in the device sunspec_client.read() except: if debug > 0: print("Cannot find the address: ", modbus_address) return False print("Found a device at address: ", modbus_address) for model in sunspec_client.device.models_list: # Name may not exist try: if model.model_type.name: print("\nName: ", model.model_type.name, "\tSunspec Id: ", model.model_type.id, "\tLabel: ", model.model_type.label) except: pass for block in model.blocks: for point in block.points_list: if point.value is not None: label = "" suns_id = (point.point_type.id).strip().upper() if point.point_type.label: label = point.point_type.label name = label + " (" + point.point_type.id + ")" units = point.point_type.units if not units: units = "" value = point.value # Replace numbered status/events with description value = convert_value(suns_id, value) print('\t%-40s %20s %-10s' % (name, value, str(units))) return True
def test_run(): result = script.RESULT_FAIL trigger = None inv = None pv = None disable = None power_max = 3050 try: ifc_type = ts.param_value('comm.ifc_type') ifc_name = ts.param_value('comm.ifc_name') if ifc_type == client.MAPPED: ifc_name = ts.param_value('comm.map_name') baudrate = ts.param_value('comm.baudrate') parity = ts.param_value('comm.parity') ipaddr = ts.param_value('comm.ipaddr') ipport = ts.param_value('comm.ipport') slave_id = ts.param_value('comm.slave_id') ts.log('Scanning EUT') try: inv = client.SunSpecClientDevice(ifc_type, slave_id=slave_id, name=ifc_name, baudrate=baudrate, parity=parity, ipaddr=ipaddr, ipport=ipport) except Exception, e: raise script.ScriptFail('Error: %s' % (e)) try: inv.settings.read() power_max = 3050 ts.log('Inverter maximum power = %d W' % (power_max)) except Exception, e: raise('Unable to get WMax setting: %s' % str(e))
def test_sunspec_client_device_3(pathlist=None): try: d = client.SunSpecClientDevice(client.MAPPED, slave_id=1, name='mbmap_test_device_3.xml', pathlist = pathlist) # int16 read and write d.model_63002.read() expected = 1111 value = int(d.model_63002.repeating[1].int16_1 * 10) if value != expected: raise Exception("'model_63002.int16_1' point mismatch: %s %s" % (value, expected)) d.model_63002.repeating[1].int16_1 = 333.3 print 'writing...' d.model_63002.write() d.model_63002.read() expected = 3333 value = int(d.model_63002.repeating[1].int16_1 * 10) if value != expected: raise Exception("'model_63002.int16_2' write failure: %s %s" % (value, expected)) expected = 2222 value = int(d.model_63002.repeating[1].int16_2 * 100) if value != expected: raise Exception("'model_63002.int16_1' point mismatch: %s %s" % (value, expected)) d.close() except Exception, e: print '*** Failure test_sunspec_client_device_3: %s' % str(e) return False
def test_run(): global inv ifc_type = ts.param_value('global.inverter.ifc_type') ifc_name = ts.param_value('global.inverter.ifc_name') baudrate = ts.param_value('global.inverter.baudrate') parity = ts.param_value('global.inverter.parity') ipaddr = ts.param_value('global.inverter.ipaddr') ipport = ts.param_value('global.inverter.ipport') slave_id = ts.param_value('global.inverter.slave_id') INV1 = ts.param_value('resets.inv1') INV2 = ts.param_value('resets.inv2') INV3 = ts.param_value('resets.inv3') VV = ts.param_value('resets.vv') print INV1, INV2, INV3, VV inv = client.SunSpecClientDevice(ifc_type, slave_id=slave_id, name=ifc_name, baudrate=baudrate, parity=parity, ipaddr=ipaddr, ipport=ipport) try: inv.read() except Exception, e: ts.log('Unable to read EUT.') return script.RESULT_FAIL
def test_sunspec_client_device_3(self): d = client.SunSpecClientDevice(client.MAPPED, slave_id=1, name='mbmap_test_device_3.xml', pathlist=self.pathlist) # int16 read and write d.model_63002.read() expected = 1111 value = int(d.model_63002.repeating[1].int16_1 * 10) if value != expected: raise Exception("'model_63002.int16_1' point mismatch: %s %s" % (value, expected)) d.model_63002.repeating[1].int16_1 = 333.3 d.model_63002.write() d.model_63002.read() expected = 3333 value = int(d.model_63002.repeating[1].int16_1 * 10) if value != expected: raise Exception("'model_63002.int16_2' write failure: %s %s" % (value, expected)) expected = 2222 value = int(d.model_63002.repeating[1].int16_2 * 100) if value != expected: raise Exception("'model_63002.int16_1' point mismatch: %s %s" % (value, expected)) d.close()
def test_sunspec_client_device_1(pathlist=None): try: d = client.SunSpecClientDevice(client.MAPPED, slave_id=1, name='mbmap_test_device_1.xml', pathlist=pathlist) d.read() dp = device.Device() dp.from_pics(filename='pics_test_device_1.xml', pathlist=pathlist) not_equal = dp.not_equal(d.device) if not_equal: raise Exception(not_equal) expected = 'SunSpecTest' if d.common.Mn != expected: raise Exception("'common.Mn' point mismatch: %s %s" % (d.common.Mn, expected)) expected = 'sn-123456789' if d.common.SN != expected: raise Exception("'common.SN' point mismatch: %s %s" % (d.common.SN, expected)) # int16 read and write d.model_63001.read() expected = -20 if d.model_63001.int16_4 != expected: raise Exception("'model_63001.int16_4' point mismatch: %s %s" % (d.model_63001.int16_4, expected)) value = 330 d.model_63001.int16_4 = value d.model_63001.write() d.model_63001.read() value = d.model_63001.int16_4 if d.model_63001.int16_4 != value: raise Exception("'model_63001.int16_4' write failure: %s %s" % (d.model_63001.int16_4, value)) # string read and write expected = '12345678' if d.model_63001.string != expected: raise Exception("'model_63001.string' point mismatch: %s %s" % (d.model_63001.string, expected)) value = 'abcdefg' d.model_63001.string = value d.model_63001.write() d.model_63001.read() if d.model_63001.string != value: raise Exception("'model_63001.string' write failure: %s %s" % (d.model_63001.string, value)) d.close() except Exception, e: print '*** Failure test_sunspec_client_device_1: %s' % str(e) return False
def test_run(): result = script.RESULT_FAIL das = None trigger = None inv = None pv = None disable = None try: ifc_type = ts.param_value('comm.ifc_type') ifc_name = ts.param_value('comm.ifc_name') if ifc_type == client.MAPPED: ifc_name = ts.param_value('comm.map_name') baudrate = ts.param_value('comm.baudrate') parity = ts.param_value('comm.parity') ipaddr = ts.param_value('comm.ipaddr') ipport = ts.param_value('comm.ipport') slave_id = ts.param_value('comm.slave_id') # Sandia Test Protocol: Communication is established between the Utility Management System Simulator # and EUT ts.log('Scanning EUT') try: inv = client.SunSpecClientDevice(ifc_type, slave_id=slave_id, name=ifc_name, baudrate=baudrate, parity=parity, ipaddr=ipaddr, ipport=ipport) except Exception, e: raise script.ScriptFail('Error: %s' % (e)) verification_delay = 5 pretest_delay = 0 # Make sure the EUT is on and operating ts.log( 'Verifying EUT is in connected state. Waiting up to %d seconds for EUT to begin power export.' % (verification_delay + pretest_delay)) if verify_initial_conn_state( inv, state=inverter.CONN_CONNECT, time_period=verification_delay + pretest_delay, das=das) is False: inv.controls.read() inv.controls.WMaxLimPct = 100 inv.controls.write() try: inv.settings.read() power_max = int(inv.settings.WMax) ts.log('Inverter maximum power = %d W' % (power_max)) except Exception, e: raise ('Unable to get WMax setting: %s' % str(e))
def connect(self): self.client = client.SunSpecClientDevice(client.TCP, self.device_id, ipaddr=self.host) #, trace=print) c_models = self.client.models if not self.models.issubset(c_models): raise Exception("requested models not present {}".format(c_models)) assert 'common' in c_models self.client.common.read() print("Connected inverter:") print(self.client.common) # TODO self._update_models() for i in self.models: self._register_model(i, getattr(self.client, i))
def test_run(): result = script.RESULT_FAIL f = None # file for saving the data try: # EUT communication parameters ifc_type = ts.param_value('comm.ifc_type') ifc_name = ts.param_value('comm.ifc_name') if ifc_type == client.MAPPED: ifc_name = ts.param_value('comm.map_name') baudrate = ts.param_value('comm.baudrate') parity = ts.param_value('comm.parity') ipaddr = ts.param_value('comm.ipaddr') ipport = ts.param_value('comm.ipport') slave_id = ts.param_value('comm.slave_id') # Data parameters duration = ts.param_value('data.duration') interval = ts.param_value('data.interval') parameters = ts.param_value('data.parameters') filename = ts.param_value('data.filename') # Sandia Test Protocol: Communication is established between the Utility Management System Simulator and EUT ts.log('Scanning EUT') try: inv = client.SunSpecClientDevice(ifc_type, slave_id=slave_id, name=ifc_name, baudrate=baudrate, parity=parity, ipaddr=ipaddr, ipport=ipport) except Exception, e: raise script.ScriptFail('Error: %s' % e) # PARSE PARAMETERS ts.log('Configuring the data capture for the following channels: %s' % parameters) formattedchans = parameters.replace(", ", "\t") formattedchans = formattedchans.replace(",", "\t") formattedchans = 'Time\tTotal_Time\t%s' % formattedchans # add python time and absolute time to channels ts.log('Channel string: %s' % formattedchans) channels = formattedchans.split() results_dir = os.path.dirname(__file__)[:-7] + 'Results' + os.path.sep if not os.path.isdir(results_dir): os.mkdir(results_dir) csv_filename = '%s%s.tsv' % (results_dir, filename) ts.log('Saving to file: %s' % csv_filename) f = open(csv_filename, 'w') try: f.write("%s\n" % formattedchans) except Exception, e: ts.log_error('Unable to save channel list to file: %s' % csv_filename)
def openConnection(device, slaveId): """ The openConnection method to open/re-open connection to the Pika """ if device: device.close() try: d = Sunspec.SunSpecClientDevice(Sunspec.TCP, slaveId, ipaddr=PIKA_IP, ipport=int(PIKA_PORT)) LOGGER.info('Modbus connection successful for slave ID: {}'.format( str(slaveId))) return d except (Exception) as ex: LOGGER.error('connection error {}'.format(ex)) return None
def connect(self): if self.fake: self.online_status = 1 else: """ Create a new inverter device """ self.online_status = 0 try: self.connection = client.SunSpecClientDevice(client.TCP, self.a, ipaddr=self.i, ipport=self.P, timeout=self.T) self.online_status = 1 except client.SunSpecClientError, e: print 'Error: %s' % (e) self.online_status = 0
def readInverter(): slaveid = 1 #126 ipaddr = '127.0.1.1' #192.168.0.111' ipport = 502 timeout = 2.0 transtype = 'tcp' try: sd = client.SunSpecClientDevice(client.TCP, slaveid, ipaddr=ipaddr, ipport=ipport, timeout=timeout) except client.SunSpecClientError as e: print('Error: %s' % (e)) sys.exit(1) if sd is not None: print('\nTimestamp: %s' % (time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime()))) sd.read() return (sd)
def get_device(self): """ @returns a device with inverter properties read """ l_modbus_slave_address = self.DEFAULT_SLAVE_ADDRESS #Default 1 if self._args.slave_address: l_modbus_slave_address = self._args.slave_address l_ip_address = self._args.host_ip self._logger.info("get_device-->IP:%s MAC:%s Slave_address:%s " % (l_ip_address, self._args.host_mac, l_modbus_slave_address)) l_timeout = 2.0 #Default 2.0 try: l_device = client.SunSpecClientDevice(client.TCP, l_modbus_slave_address, ipaddr=l_ip_address, timeout=l_timeout) l_device.common.read() # retreives latest inverter model contents l_device.inverter.read() # retreives latest inverter model contents return l_device except client.SunSpecClientError as l_e: self._logger.error('SunspecClientError: %s' % (l_e)) raise l_e except Exception as l_e: self._logger.exception("Exception occured: %s" % (l_e)) self._logger.error('Error: %s' % (l_e)) raise l_e
def __init__(self, conn_type=None, slave_id=126, name=None, pathlist=None, baudrate=None, parity=None, ip=None, port=None, timeout=60, trace=False): ''' Creates an Sunspec client instance to communicate with the Inverter ''' self.device = None try: conn = client.TCP if conn_type == "TCP": conn = client.TCP elif conn_type == "RTU": conn = client.RTU elif conn_type == "MAPPED": conn = client.MAPPED if not DEBUG: self.device = client.SunSpecClientDevice( conn, slave_id, name, pathlist, baudrate, parity, ip, port, timeout, trace) self.model_map = self.get_device_models() _log.info("Available models in the inverter: %s" % self.device.models) except SunSpecClientError, s: if device_type == client.MAPPED: _log.error("Map file required") else: _log.error("Inverter failed to initialize%s" % s)
import sunspec import sunspec.core.client as client d = client.SunSpecClientDevice(client.RTU, 1, 'COM4', max_count=10) print(d.models) d.common.read() print(d.common) print(d.common.points) print(d.common.Opt) print(d.common.Vr)
def sunspec_test(ip, port, address): """ Original suns options: -o: output mode for data (text, xml) -x: export model description (slang, xml) -t: transport type: tcp or rtu (default: tcp) -a: modbus slave address (default: 1) -i: ip address to use for modbus tcp (default: localhost) -P: port number for modbus tcp (default: 502) -p: serial port for modbus rtu (default: /dev/ttyUSB0) -b: baud rate for modbus rtu (default: 9600) -T: timeout, in seconds (can be fractional, such as 1.5; default: 2.0) -r: number of retries attempted for each modbus read -m: specify model file -M: specify directory containing model files -s: run as a test server -I: logger id (for sunspec logger xml output) -N: logger id namespace (for sunspec logger xml output, defaults to 'mac') -l: limit number of registers requested in a single read (max is 125) -c: check models for internal consistency then exit -v: verbose level (up to -vvvv for most verbose) -V: print current release number and exit """ try: sd = client.SunSpecClientDevice(client.TCP, address, ipaddr=ip, ipport=port, timeout=10.0) except client.SunSpecClientError as e: print('Error: %s' % (e)) sys.exit(1) if sd is not None: print('\nTimestamp: %s' % (time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime()))) # read all models in the device sd.read() root = ET.Element(pics.PICS_ROOT) sd.device.to_pics(parent=root, single_repeating=True) print(minidom.parseString(ET.tostring(root)).toprettyxml(indent=" ")) for model in sd.device.models_list: if model.model_type.label: label = '%s (%s)' % (model.model_type.label, str(model.id)) else: label = '(%s)' % (str(model.id)) print('\nmodel: %s\n' % (label)) for block in model.blocks: if block.index > 0: index = '%02d:' % (block.index) else: index = ' ' for point in block.points_list: if point.value is not None: if point.point_type.label: label = ' %s%s (%s):' % (index, point.point_type.label, point.point_type.id) else: label = ' %s(%s):' % (index, point.point_type.id) units = point.point_type.units if units is None: units = '' if point.point_type.type == suns.SUNS_TYPE_BITFIELD16: value = '0x%04x' % (point.value) elif point.point_type.type == suns.SUNS_TYPE_BITFIELD32: value = '0x%08x' % (point.value) else: value = str(point.value).rstrip('\0') print('%-40s %20s %-10s' % (label, value, str(units)))
sunspec_ip = arguments["--sunspec_ip"] sunspec_port = int(arguments["--sunspec_port"]) sunspec_address = arguments["--sunspec_address"] if arguments["query"]: sunspec_test(sunspec_ip, sunspec_port, sunspec_address) sys.exit(0) if arguments["start"]: sunspec_model_ids = arguments["--sunspec_model_ids"].split(",") try: sunspec_client = client.SunSpecClientDevice(client.TCP, sunspec_address, ipaddr=sunspec_ip, ipport=sunspec_port, timeout=10.0) except client.SunSpecClientError as e: print('Error: %s' % (e)) sys.exit(1) # remove the models that don't match what we want # this will make reads faster (ignore unnecessary model data sets) filters = [] if arguments["--filter"] is not None: for f in arguments["--filter"]: (filter_metric_regex, func_n_params, replacement) = f.split(" ") func_name, *parameters = func_n_params.split(":")
import sunspec import sunspec.core.client as client import time #.40 is ESS #.41 is PV ESS = client.SunSpecClientDevice(client.TCP, 1, ipaddr='192.168.10.41', max_count=10) #PV = client.SunSpecClientDevice(client.TCP, 1, ipaddr='192.168.10.40', max_count=10) #print sunpec models print(ESS.models) #Read common model ESS.common.read() print(ESS.common) #Set to control source 0=CAN 1=Modbus ESS.epc.read() print(ESS.epc) ESS.epc.CtlSrc = 1 ESS.epc.write() ESS.inverter.read() if ESS.inverter.StVnd == 3: #stop ESS.epc.CmdBits = 4648 ESS.epc.write() ESS.epc.read()
import sunspec.core.client as client import model_manipulation as mm def leaving(data): data.close() parser = argparse.ArgumentParser("modbus_influxdb") parser.add_argument("ip", help="The address of the device.", type=str) parser.add_argument("db", help="InfluxDB name.", type=str) args = parser.parse_args() data = client.SunSpecClientDevice(client.TCP, 1, ipaddr=args.ip, ipport=502, timeout=20000) atexit.register(leaving, data) db_client = InfluxDBClient('localhost', 8086, 'root', 'root', args.db) db_client.create_database(args.db) models_array = [ #"common", #"model_10", #"model_11", #"model_12", "inverter", "model_65001", "model_65002",
def test_run(): result = script.RESULT_FAIL data = None trigger = None grid = None pv = None inv = None freq = {} W = {} disable = None try: ifc_type = ts.param_value('comm.ifc_type') ifc_name = ts.param_value('comm.ifc_name') if ifc_type == client.MAPPED: ifc_name = ts.param_value('comm.map_name') baudrate = ts.param_value('comm.baudrate') parity = ts.param_value('comm.parity') ipaddr = ts.param_value('comm.ipaddr') ipport = ts.param_value('comm.ipport') slave_id = ts.param_value('comm.slave_id') freq_ref = ts.param_value( 'fw.settings.freq_ref') # is there a sunspec parameter for this? fw_mode = ts.param_value('fw.settings.fw_mode') #fw_mode == 'FW21 (FW parameters)': WGra = ts.param_value('fw.settings.WGra') HzStr = ts.param_value('fw.settings.HzStr') HzStop = ts.param_value('fw.settings.HzStop') HysEna = ts.param_value('fw.settings.HysEna') HzStopWGra = ts.param_value('fw.settings.HzStopWGra') #'FW22 (pointwise FW)' time_window = ts.param_value('fw.settings.time_window') timeout_period = ts.param_value('fw.settings.timeout_period') ramp_time = ts.param_value('fw.settings.ramp_time') recovery_ramp_rate = ts.param_value('fw.settings.recovery_ramp_rate') curve_num = ts.param_value('fw.settings.curve_num') n_points = ts.param_value('fw.settings.n_points') freq = ts.param_value('fw.curve.freq') W = ts.param_value('fw.curve.W') pretest_delay = ts.param_value('invt.pretest_delay') power_range = ts.param_value('invt.power_range') setpoint_failure_count = ts.param_value('invt.setpoint_failure_count') setpoint_period = ts.param_value('invt.setpoint_period') verification_delay = ts.param_value('invt.verification_delay') posttest_delay = ts.param_value('invt.posttest_delay') disable = ts.param_value('invt.disable') # initialize data acquisition system daq = das.das_init(ts) data = daq.data_init() trigger = daq.trigger_init() # initialize pv simulation pv = pvsim.pvsim_init(ts) pv.power_on() # initialize grid simulation grid = gridsim.gridsim_init(ts) grid.profile_load(ts.param_value('profile.profile_name')) # Sandia Test Protocol: Communication is established between the Utility Management System Simulator and EUT # EUT scan after grid and PV simulation setup so that Modbus registers can be read. ts.log('Scanning inverter') inv = client.SunSpecClientDevice(ifc_type, slave_id=slave_id, name=ifc_name, baudrate=baudrate, parity=parity, ipaddr=ipaddr, ipport=ipport) # Make sure the EUT is on and operating ts.log( 'Verifying EUT is in connected state. Waiting up to %d seconds for EUT to begin power export.' % (verification_delay + pretest_delay)) if verify_initial_conn_state( inv, state=inverter.CONN_CONNECT, time_period=verification_delay + pretest_delay, das=data) is False: ts.log_error('Inverter unable to be set to connected state.') raise script.ScriptFail() ######## Begin Test ######## if pretest_delay > 0: ts.log('Waiting for pre-test delay of %d seconds' % pretest_delay) ts.sleep(pretest_delay) # Request status and display power freq_original = inverter.get_freq(inv, das=data) power_original = inverter.get_power(inv, das=data) ts.log('Current grid frequency is %.3f Hz and EUT power is %.3f W' % (freq_original, power_original)) ### todo: open the ride-through settings at this point to ensure the EUT doesn't trip during freq profile. # ts.log_debug('%s, %s, %s, %s, %s' % (WGra, HzStr, HzStop, HysEna, HzStopWGra)) if HzStopWGra == 0: ts.log_warning( 'Setting HzStopWGra to 10000 because of the limits of the EUT. This is the fastest available option.' ) inverter.set_freq_watt(inv, fw_mode=fw_mode, freq=freq, W=W, n_points=n_points, curve_num=curve_num, timeout_period=timeout_period, ramp_time=ramp_time, recovery_ramp_rate=recovery_ramp_rate, time_window=time_window, WGra=WGra, HzStr=HzStr, HzStop=HzStop, HysEna=HysEna, HzStopWGra=HzStopWGra, enable=1, trigger=trigger) # Run the grid simulator profile immediately after setting the freq-watt functions and triggering if grid is not None: ts.log('Running frequency profile.') grid.profile_start() # power_pass_fail_band only determines the point on the curve. It does not account for hysteresis. pow_targ, pow_upper, pow_lower = power_pass_fail_band( inv, fw_mode=fw_mode, freq=freq, W=W, n_points=n_points, power_range=power_range, WGra=WGra, HzStr=HzStr, freq_ref=freq_ref, das=das) ts.log( 'Target power: %.3f. Pass limits for screening: upper = %.3f lower = %.3f' % (pow_targ, pow_upper, pow_lower)) # Log FW parameters and calculate test_duration test_duration = setpoint_period + verification_delay ts.log( 'Waiting up to %d seconds for power change with a verification period of %d seconds.' % (ramp_time + time_window, verification_delay)) ts.log_debug('dc_voltage = %0.3f' % data.dc_voltage) ts.log_debug('dc_current = %0.3f' % data.dc_current) ts.log_debug('ac_voltage = %0.3f' % data.ac_voltage) ts.log_debug('ac_current = %0.3f' % data.ac_current) ts.log_debug('dc_watts = %0.3f' % data.dc_watts) ts.log_debug('Power = %0.3f' % data.ac_watts) ts.log_debug('ac_freq = %0.3f' % data.ac_freq) ts.log_debug('trigger = %0.3f' % data.trigger) start_time = time.time() elapsed_time = 0 # Initialize consecutive failure count to not script fail on transient behavior failures = 0 revert_complete = False in_hysteresis = False # flag for when the FW is in hysteresis inv.nameplate.read() max_W = float(inv.nameplate.WRtg) if time_window != 0: window_complete = False else: window_complete = True time_window_execution = time_window while elapsed_time <= test_duration: ts.sleep(0.93) elapsed_time = time.time() - start_time power_pct = (inverter.get_power(inv, das=data) / max_W) * 100. #determine if function is in hysteresis if fw_mode == 'FW21 (FW parameters)' and HysEna == 'Yes': freq_new = inverter.get_freq(inv, das=data) if freq_new < freq_original and freq_original > HzStr: if not in_hysteresis: in_hysteresis = True hys_power = power_pct ts.log( 'Entered the Hysteresis band with power limit = %0.3f%%' % hys_power) else: ts.log( 'Still in the Hysteresis band with power limited to %0.3f%%' % hys_power) elif in_hysteresis and freq_new < HzStop: in_hysteresis = False # No longer in hysteresis band ts.log( 'Exited hysteresis band. Returning to FW curve power at HzStopWGra = %0.3f %%nameplate/min' % HzStopWGra) freq_original = freq_new if window_complete is True and revert_complete is False: if in_hysteresis is False: # pow_targ, pow_upper, pow_lower are in percentages of nameplate power pow_targ, pow_upper, pow_lower = power_pass_fail_band( inv, fw_mode=fw_mode, freq=freq, W=W, n_points=n_points, power_range=power_range, WGra=WGra, HzStr=HzStr, freq_ref=freq_ref, das=data) else: # in hysteresis band pow_targ = hys_power pow_upper = pow_targ + power_range # units of % nameplate watts pow_lower = pow_targ - power_range # units of % nameplate watts else: # Before the time window executes and after timeout period, the upper and lower pass/fail bounds for EUT # use the default power state of 100% Wmax pow_targ = 100. pow_upper = pow_targ + power_range # units of % nameplate watts pow_lower = pow_targ - power_range # units of % nameplate watts ts.log( 'W Target = %.3f [%.3f to %.3f], W = %.3f (Error = %0.3f%%), Time: %0.3f seconds.' % (pow_targ, pow_lower, pow_upper, power_pct, (power_pct - pow_targ), elapsed_time)) if revert_complete is False: #if testing FW21, timing parameters are all 0, so they don't affect results # Check when the EUT is in range for the first time if window_complete is False and \ inverter.get_active_control_status(inv, inverter.STACTCTL_FREQ_WATT_PARAM): window_complete = True time_window_execution = elapsed_time ts.log( 'Randomization window occurred at %0.3f seconds, current power %.3f.' % (time_window_execution, power_pct)) # Check for timeout period (reversion) if window_complete and timeout_period != 0: if not inverter.get_active_control_status( inv, inverter.STACTCTL_FREQ_WATT_PARAM): #reverted revert_complete = True ts.log( 'Reversion occurred at timeout period = %0.3f seconds, current power %.3f.' % (elapsed_time, power_pct)) # Did timeout_period fail? If so, end the test here. # Note: there's a final timeout_period check outside the while loop. elif elapsed_time >= timeout_period + min( time_window, time_window_execution) + verification_delay: ts.log_error( 'Inverter did not revert after %0.3f seconds.' % elapsed_time) raise script.ScriptFail() # if power out of range if power_pct < pow_lower or power_pct > pow_upper: ts.log_debug( 'Power %0.3f, Pow Lower = %0.3f, Pow Upper = %0.3f.' % (power_pct, pow_lower, pow_upper)) # There are three acceptable sources of noncompliance. If the randomization window hasn't occurred, # the reversion (timeout) occurred, or it is ramping to the target vars if window_complete is False: #time window ts.log( 'Randomization window still in effect after %0.3f seconds.' % (time.time() - start_time)) elif elapsed_time > min(time_window, time_window_execution) + ramp_time: # Noncompliance is not from time period, time window, or ramp rate # Count this as a failure failures += 1 if failures >= setpoint_failure_count: ts.log_error( 'Inverter exceeded var setpoint + buffer after %0.3f seconds. ' 'Fail count = %d.' % (elapsed_time, failures)) raise script.ScriptFail() else: ts.log_warning( 'Inverter exceeded var setpoint + buffer after %0.3f seconds. ' 'Fail count = %d.' % (elapsed_time, failures)) else: ts.log_warning( 'EUT has not reached the target reactive power because it is ramping.' ) else: failures = 0 # Additional timeout check to determine if the timeout_period occurred during the test. This is necessary # in cases where the verification_delay is not set sufficiently long. if timeout_period != 0 and inverter.get_active_control_status( inv, inverter.STACTCTL_VOLT_VAR): ts.log_error( 'Inverter did not revert by the end of the test duration. Elapsed time = %0.3f seconds. ' 'Increase the verification period if the timeout period is greater than the elapsed time.' % (elapsed_time)) raise script.ScriptFail() if posttest_delay > 0: ts.log('Waiting for post-test delay of %d seconds' % posttest_delay) ts.sleep(posttest_delay) result = script.RESULT_PASS except script.ScriptFail, e: reason = str(e) if reason: ts.log_error(reason)
ipaddr = socket.gethostbyname(socket.gethostname()) print('This machine has the following default IP: %s' % ipaddr) ip_values = ipaddr.split(".") for i in range(256): # ip = '%s.%s.%s.%s' % (ip_values[0], ip_values[1], ip_values[2], i) ip = '%s.%s.%s.%s' % (10, 1, 2, i) for ipport in ipports: for slave_id in slave_ids: try: print('Communicating to %s on port %s with slave_id %s' % (ip, ipport, slave_id)) device = client.SunSpecClientDevice(client.TCP, slave_id=slave_id, ipaddr=ip, ipport=ipport, timeout=timeout) # device = client.ModbusClientDeviceTCP(slave_id=slave_id, ipaddr=ip, ipport=ipport, timeout=timeout) params = {} device.common.read() params['Manufacturer'] = device.common.Mn params['Model'] = device.common.Md params['Options'] = device.common.Opt params['Version'] = device.common.Vr params['SerialNumber'] = device.common.SN print('This is a %s %s device' % (params['Manufacturer'], params['Model'])) except Exception, e: print('Error: %s' % e)
# Change these values to match your connection, DSO regulation and system as a whole. Be careful changing them, only higher them if you are really sure. maxChargeValue = -2000 maxDischargeValue = 2000 # # The modbus registers to activate the communication and the power control address activateControlAddress = 40151 changePowerAddress = 40149 # try: # Controlling the battery via SunSpec showed some issues, thus SunSpec is only used to read out the battery # Slave ID is 126 because this is the SunSpec Slave ID sunSpecClient = clientSunspec.SunSpecClientDevice(clientSunspec.TCP, 126, ipaddr=modbusInverterIP, ipport=502, timeout=2.0) except: print("Error connecting to the inverter via SunSpec") try: # Slave ID is 3 because this is the right ID for controlling the charge/discharge power modbusClient = ModbusClient(modbusInverterIP, port=502, unit_id=3, auto_open=True, auto_close=True) except: print("Error connecting to the inverter via plain Modbus")
import json import time import sunspec.core.client as client import time import sys d = client.SunSpecClientDevice(client.TCP, 1, ipaddr="192.168.0.107", ipport=1502) time.sleep(0.5) #print (d.models) #print d.inverter.points now = time.time() time.sleep(2) print(time.time() - now) while True: # d = client.SunSpecClientDevice(client.TCP, 1, ipaddr="192.168.0.107", ipport=1502) d.inverter.read() d.ac_meter.read() #dumped = json.dumps(d) #print(dumped) dict = {} for (key, value) in d.inverter.model.__dict__.items(): #print(key) if (key == "points"):
def test_sunspec_client_device_1(self): d = client.SunSpecClientDevice(client.MAPPED, slave_id=1, name='mbmap_test_device_1.xml', pathlist=self.pathlist) d.read() dp = device.Device() dp.from_pics(filename='pics_test_device_1.xml', pathlist=self.pathlist) not_equal = dp.not_equal(d.device) if not_equal: raise Exception(not_equal) expected = 'SunSpecTest' if d.common.Mn != expected: raise Exception("'common.Mn' point mismatch: %s %s" % (d.common.Mn, expected)) expected = 'sn-123456789' if d.common.SN != expected: raise Exception("'common.SN' point mismatch: %s %s" % (d.common.SN, expected)) # int16 read and write d.model_63001.read() expected = -20 if d.model_63001.int16_4 != expected: raise Exception("'model_63001.int16_4' point mismatch: %s %s" % (d.model_63001.int16_4, expected)) value = 330 d.model_63001.int16_4 = value d.model_63001.write() d.model_63001.read() value = d.model_63001.int16_4 if d.model_63001.int16_4 != value: raise Exception("'model_63001.int16_4' write failure: %s %s" % (d.model_63001.int16_4, value)) # string read and write expected = '12345678' if d.model_63001.string != expected: raise Exception("'model_63001.string' point mismatch: %s %s" % (d.model_63001.string, expected)) value = 'abcdefg' d.model_63001.string = value d.model_63001.write() d.model_63001.read() if d.model_63001.string != value: raise Exception("'model_63001.string' write failure: %s %s" % (d.model_63001.string, value)) # write multiple d.model_63001.read() expected = 65524 if d.model_63001.uint16_3 != expected: raise Exception("'model_63001.uint16_3' point mismatch: %s %s" % (d.model_63001.uint16_3, expected)) expected = 60 if d.model_63001.uint16_4 != expected: raise Exception("'model_63001.uint16_4' point mismatch: %s %s" % (d.model_63001.uint16_4, expected)) expected = 7 if d.model_63001.uint16_5 != expected: raise Exception("'model_63001.uint16_5' point mismatch: %s %s" % (d.model_63001.uint16_5, expected)) value_3 = 65525 value_4 = 70 value_5 = 8 d.model_63001.uint16_3 = value_3 d.model_63001.uint16_4 = value_4 d.model_63001.uint16_5 = value_5 d.model_63001.write() d.model_63001.read() value = d.model_63001.uint16_3 if d.model_63001.uint16_3 != value_3: raise Exception("'model_63001.int16_3' write failure: %s %s" % (d.model_63001.uint16_3, value_3)) value = d.model_63001.uint16_4 if d.model_63001.uint16_4 != value_4: raise Exception("'model_63001.int16_4' write failure: %s %s" % (d.model_63001.uint16_4, value_4)) value = d.model_63001.uint16_5 if d.model_63001.uint16_5 != value_5: raise Exception("'model_63001.int16_5' write failure: %s %s" % (d.model_63001.uint16_5, value_5)) # write multiple d.model_63001.read() expected = value_3 if d.model_63001.uint16_3 != expected: raise Exception("'model_63001.uint16_3' point mismatch: %s %s" % (d.model_63001.uint16_3, expected)) expected = value_4 if d.model_63001.uint16_4 != expected: raise Exception("'model_63001.uint16_4' point mismatch: %s %s" % (d.model_63001.uint16_4, expected)) expected = value_5 if d.model_63001.uint16_5 != expected: raise Exception("'model_63001.uint16_5' point mismatch: %s %s" % (d.model_63001.uint16_5, expected)) value_3 = 65524 value_5 = 7 d.model_63001.uint16_3 = value_3 d.model_63001.uint16_5 = value_5 d.model_63001.write() d.model_63001.read() value = d.model_63001.uint16_3 if d.model_63001.uint16_3 != value_3: raise Exception("'model_63001.int16_3' write failure: %s %s" % (d.model_63001.uint16_3, value_3)) value = d.model_63001.uint16_4 if d.model_63001.uint16_4 != value_4: raise Exception("'model_63001.int16_4' write failure: %s %s" % (d.model_63001.uint16_4, value_4)) value = d.model_63001.uint16_5 if d.model_63001.uint16_5 != value_5: raise Exception("'model_63001.int16_5' write failure: %s %s" % (d.model_63001.uint16_5, value_5)) d.close()
#!/usr/bin/env python import sunspec.core.client as client import sunspec.core.suns as suns from elasticsearch import Elasticsearch from datetime import datetime es = Elasticsearch([{'host': 'nuccie.local', 'port': 9200}]) try: sd = client.SunSpecClientDevice(client.TCP, 1, ipaddr="192.168.0.158", ipport=502, timeout=2.0) except client.SunSpecClientError, e: print('Error: %s' % (e)) sys.exit(1) data = {} if sd is not None: sd.read() for model in sd.device.models_list: if model.model_type.label: label = '%s (%s)' % (model.model_type.label, str(model.id)) else: label = '(%s)' % (str(model.id)) print('\nmodel: %s\n' % (label)) for block in model.blocks:
def get_sunspec_data(self): self.logger.info('Creating SunSpec modbus TCP client,' ' Host: {0} - Port: {1} - DeviceID: {2}' .format(self.host, self.port, self.device_id)) try: d = client.SunSpecClientDevice(client.TCP, slave_id= self.device_id, ipaddr=self.host, ipport=self.port, timeout=5) self.logger.info('Trying to fetch SunSpec data from ModBus') self.logger.debug('Fetching Models: {0}'.format(d.models)) d.common.read() self.logger.debug('Reading SunSpec Common Model_1:' ' {0}'.format(d.common)) d.inverter.read() self.logger.debug('Reading SunSpec Inverter Model_101:' ' {0}'.format(d.inverter)) d.mppt.read() self.logger.debug('Reading SunSpec MPPT Model_106:' ' {0}'.format(d.mppt)) d.nameplate.read() self.logger.debug('Reading SunSpec NamePlate Model_120:' ' {0}'.format(d.nameplate)) d.settings.read() self.logger.debug('Reading SunSpec Settings Model_121:' ' {0}'.format(d.settings)) d.controls.read() self.logger.debug('Reading SunSpec Controls Model_123:' ' {0}'.format(d.controls)) # Only return relevant data suns_data = { 'A': d.inverter.A, 'PhVphA': d.inverter.PhVphA, 'W': d.inverter.W, 'Hz': d.inverter.Hz, 'WH': d.inverter.WH, 'DCW': d.inverter.DCW, 'TmpOt': d.inverter.TmpOt, 'St': d.inverter.St, 'StVnd': d.inverter.StVnd, 'DCA_1': d.mppt.module[1].DCA, 'DCV_1': d.mppt.module[1].DCV, 'DCW_1': d.mppt.module[1].DCW, 'DCA_2': d.mppt.module[2].DCA, 'DCV_2': d.mppt.module[2].DCV, 'DCW_2': d.mppt.module[2].DCW, } # Filter none suns_data2 = {k: v for k, v in suns_data.items() if v is not None} self.logger.info('Fetched SunSpec data points: {0}'. format(suns_data2)) return suns_data2 except Exception as e: self.logger.error(e) return None
import sunspec.core.client as client d = client.SunSpecClientDevice(client.RTU, 1, "com6") print(d.models)
def test_run(): result = script.RESULT_FAIL data = None trigger = None inv = None pv = None disable = None try: # EUT communication parameters ifc_type = ts.param_value('comm.ifc_type') ifc_name = ts.param_value('comm.ifc_name') if ifc_type == client.MAPPED: ifc_name = ts.param_value('comm.map_name') baudrate = ts.param_value('comm.baudrate') parity = ts.param_value('comm.parity') ipaddr = ts.param_value('comm.ipaddr') ipport = ts.param_value('comm.ipport') slave_id = ts.param_value('comm.slave_id') # INV1 parameters operation = ts.param_value('inv1.operation') time_window = ts.param_value('inv1.time_window') timeout_period = ts.param_value('inv1.timeout_period') # Script timing and pass/fail criteria pretest_delay = ts.param_value('invt.pretest_delay') verification_delay = ts.param_value('invt.verification_delay') posttest_delay = ts.param_value('invt.posttest_delay') power_threshold = ts.param_value('invt.power_threshold') disable = ts.param_value('invt.disable') # initialize data acquisition system daq = das.das_init(ts) data = daq.data_init() trigger = daq.trigger_init() # initialize pv simulation pv = pvsim.pvsim_init(ts) pv.power_on() # It is assumed that the PV and Grid Simulators (if used) are connected to the EUT and operating properly # prior to running this test script. if pretest_delay > 0: ts.log('Waiting for pre-test delay of %d seconds' % pretest_delay) ts.sleep(pretest_delay) # Sandia Test Protocol: Communication is established between the Utility Management System Simulator and EUT ts.log('Scanning EUT') try: inv = client.SunSpecClientDevice(ifc_type, slave_id=slave_id, name=ifc_name, baudrate=baudrate, parity=parity, ipaddr=ipaddr, ipport=ipport) except Exception, e: raise script.ScriptFail('Error: %s' % e) # Define operation states (connected/disconnected) # Default state is required for timeout_periods because the EUT will return to that mode of operation default_state = inverter.CONN_CONNECT if operation == 'Connect': orig_state = inverter.CONN_DISCONNECT state = inverter.CONN_CONNECT elif operation == 'Disconnect': orig_state = inverter.CONN_CONNECT state = inverter.CONN_DISCONNECT else: ts.log('Unknown operation requested: %s' % operation) raise script.ScriptFail() # Sandia Test Protocol Step 1: Request Status of EUT. # Sandia Test Protocol Step 2: UMS receives response to the DS93 command. # Verify EUT is in correct state before running the test. if inverter.verify_conn_state(inv, orig_state, threshold=power_threshold, das=data) is False: # todo: update inverter module with das changed to data ts.log('Inverter not in correct state, setting state to: %s' % (inverter.conn_state_str(orig_state))) # EUT put into state where INV1 can be verified inverter.set_conn_state(inv, orig_state) if verify_conn_state_change(inv, orig_state, verification_delay=verification_delay, threshold=power_threshold, data=data) is False: raise script.ScriptFail() # Sandia Test Protocol Step 3: Inverter output is measured and logged. log_conn_state(inv, data=data) # Sandia Test Protocol Step 4: UMS issues the INV1 command. ts.log('Executing %s' % operation) inverter.set_conn_state(inv, state, time_window=time_window, timeout_period=timeout_period, trigger=trigger) # Sandia Test Protocol Step 5: Verify the INV1 command was successfully executed. if verify_conn_state_change(inv, state, time_window=time_window, verification_delay=verification_delay, threshold=power_threshold, data=data) is False: raise script.ScriptFail() # Verify revert (timeout) to default state if timeout period specified if timeout_period > 0: if verify_conn_state_change(inv, default_state, timeout_period=timeout_period, verification_delay=verification_delay, threshold=power_threshold, data=data) is False: raise script.ScriptFail() if posttest_delay > 0: ts.log('Waiting for post-test delay of %d seconds' % posttest_delay) ts.sleep(posttest_delay) result = script.RESULT_PASS
parser.add_option( '-T', metavar=' ', type='float', default=2.0, help= 'timeout, in seconds (can be fractional, such as 1.5) [default: 2.0]') parser.add_option('-m', metavar=' ', help='modbus map file') options, args = parser.parse_args() try: if options.t == 'tcp': sd = client.SunSpecClientDevice(client.TCP, options.a, ipaddr=options.i, ipport=options.P, timeout=options.T) elif options.t == 'rtu': sd = client.SunSpecClientDevice(client.RTU, options.a, name=options.p, baudrate=options.b, timeout=options.T) elif options.t == 'mapped': sd = client.SunSpecClientDevice(client.MAPPED, options.a, name=options.m) else: print('Unknown -t option: %s' % (options.t)) sys.exit(1)
def device(self, ifc='tcp', ipaddr='127.0.0.1', ipport=502, slaveid=1, timeout=5, name=None, baudrate=9600, parity='N'): # return '{"status": "SUCCESS", "result": "device output - ipaddr = %s ipport = %d timeout = %d"}' % (ipaddr, ipport, timeout) status = 'SUCCESS' status_detail = '' result = '' jsonResult = '' try: if ifc == 'tcp': status_detail += 'IP Address: %s, IP Port: %d, Slave Id: %d, Timeout: %d, ' % ( ipaddr, ipport, slaveid, timeout) # sd = client.SunSpecClientDevice(client.TCP, slaveid, ipaddr=ipaddr, ipport=ipport, timeout=timeout) sd = client.SunSpecClientDevice(client.TCP, slaveid, ipaddr=ipaddr, ipport=ipport, timeout=5) elif ifc == 'rtu': sd = client.SunSpecClientDevice(client.RTU, slaveid, name=name, baudrate=baudrate, timeout=timeout) elif ifc == 'mapped': sd = client.SunSpecClientDevice(client.MAPPED, slaveid, name=name) else: raise Exception('Invalid ifc param type: %s' % ifc) status_detail += 'Timestamp: %s' % (time.strftime( '%Y-%m-%dT%H:%M:%SZ', time.gmtime())) if sd is not None: # read all models in the device sd.read() # jsonResult = json.dumps( sd ) # NB: the following loop is not actually used - we return 'sd' to the client, & they sort it themselves # One day, I hope to be able to get json serialization working! for model in sd.device.models_list: if model.model_type.label: label = '%s (%s)' % (model.model_type.label, str(model.id)) else: label = '(%s)' % (str(model.id)) result += '{"model":' result += '{"name":"%s",' % (label) result += '"value":"' for block in model.blocks: if block.index > 0: index = '%02d-' % (block.index) else: index = ' ' for point in block.points_list: if point.value is not None: if point.point_type.label: label = ' %s%s (%s)-' % ( index, point.point_type.label, point.point_type.id) else: label = ' %s(%s)-' % ( index, point.point_type.id) units = point.point_type.units if units is None: units = '' if point.point_type.type == suns.SUNS_TYPE_BITFIELD16: value = '0x%04x' % (point.value) elif point.point_type.type == suns.SUNS_TYPE_BITFIELD32: value = '0x%08x' % (point.value) else: value = str(point.value).rstrip('\0') result += '%-20s %10s %-10s' % (label, value, str(units)) result += '"},' result += '"}' except Exception, e: status = 'FAILURE' status_detail = str(e)