Skip to content
12 changes: 6 additions & 6 deletions dnp3-master/service/config/device_ip_port_config.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
{
"RTU1": {
"RTU1": {
"name": "RTU1",
"conversion_type": "RTU1",
"CIM object": "l50",
"port": "20000",
"ip": "172.20.128.199",
"port": "30000",
"ip": "127.0.0.1",
"desc": "RTU1",
"link_local_addr": "101",
"link_remote_addr": "43"
"link_local_addr": "2",
"link_remote_addr": "1"
}
}
}
62 changes: 62 additions & 0 deletions dnp3-master/service/config/new_conversion_dict_master.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
{
"RTU1": {
"Binary input": {
"0": {
"index": 0,
"original_name": "ufls_59.1",
"Type of Object": "Protection Relay",
"CIM attribute": "FunctionBlock.enabled",
"CIM name": "ufls_59.1",
"CIM phase": "ABC",
"CIM Variable": "Pos",
"CIM units": "",
"CIM type": "Pos",
"Multiplier": 1,
"CIM Var type": "magnitude"
},
"1": {
"index": 1,
"original_name": "ufls_59.5",
"Type of Object": "Protection Relay",
"CIM attribute": "FunctionBlock.enabled",
"CIM name": "ufls_59.5",
"CIM phase": "ABC",
"CIM Variable": "Pos",
"CIM units": "",
"CIM type": "Pos",
"Multiplier": 1,
"CIM Var type": "magnitude"
}
},
"Binary output": {
"0": {
"index": 0,
"original_name": "ufls_59.1",
"Type of Object": "Protection Relay",
"CIM attribute": "FunctionBlock.enabled",
"CIM name": "ufls_59.1",
"CIM phase": "ABC",
"CIM Variable": "pos",
"CIM units": "",
"CIM type": "Pos",
"Multiplier": 1,
"CIM Value Type": "magnitude",
"CIM mRID": "1d88371e-3db5-4b23-b8cd-fc0f2f3569fb"
},
"1": {
"index": 1,
"original_name": "ufls_59.5",
"Type of Object": "Protection Relay",
"CIM attribute": "FunctionBlock.enabled",
"CIM name": "ufls_59.5",
"CIM phase": "ABC",
"CIM Variable": "pos",
"CIM units": "",
"CIM type": "Pos",
"Multiplier": 1,
"CIM Value Type": "magnitude",
"CIM mRID": "a9eb2b35-c340-4d31-9a0a-4ff2d4463361"
}
}
}
}
22 changes: 22 additions & 0 deletions dnp3-master/service/config/new_measurement_dict_master.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"ufls_59.1": {
"Pos": {
"ABC": [
{
"mrid": "1d88371e-3db5-4b23-b8cd-fc0f2f3569fb",
"type": "value"
}
]
}
},
"ufls_59.5": {
"Pos": {
"ABC": [
{
"mrid": "a9eb2b35-c340-4d31-9a0a-4ff2d4463361",
"type": "value"
}
]
}
}
}
23 changes: 23 additions & 0 deletions dnp3-master/service/config/new_model_line_dict.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"ufls_59.1": {
"Pos": {
"ABC": [
{
"mrid": "1d88371e-3db5-4b23-b8cd-fc0f2f3569fb",
"type": "value"
}
]
}
},
"ufls_59.5": {
"Pos": {
"ABC": [
{
"mrid": "a9eb2b35-c340-4d31-9a0a-4ff2d4463361",
"type": "value"
}
]
}
}
}

143 changes: 132 additions & 11 deletions dnp3-master/service/start_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
import numpy as np
import yaml
import logging
import gridappsd.topics as topics

from dnp3.CIMPro_AIAO_BIBO import CIMProcessor

Expand All @@ -50,6 +51,27 @@
from gridappsd.topics import simulation_output_topic, simulation_input_topic
from gridappsd import GridAPPSD, DifferenceBuilder, utils

# from dnp3_python.dnp3station.master import MyMaster
from dnp3_python.dnp3station.master_new import MyMasterNew

# TODO: clean up the custom logger later
# Create a logger object
logger = logging.getLogger('my_logger')
logger.setLevel(logging.DEBUG) # Set the minimum logging level

# Create a file handler for outputting logs to a file
file_handler = logging.FileHandler('/home/shared_user/gridappsd-dnp3-master/dnp3-master/service/myfile.log')
file_handler.setLevel(logging.INFO) # Only log error and above messages to the file

# Create a formatter
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
file_handler.setFormatter(formatter)

# Add handlers to the logger
logger.addHandler(file_handler)

# TODO: clean up the custom logger later === (END)

myCIMProcessor = None

logging.basicConfig(level=logging.DEBUG)
Expand All @@ -72,8 +94,10 @@ def run_master(device_ip_port_config_all_13bus, names,simulation_id,gapps,dnp3_t
convertion_type=device_ip_port_dict[
'conversion_type']
object_name=device_ip_port_dict['CIM object']

logger.info(f"{HOST=}") # TODO: kefei added

application_1 = MyMaster(HOST=HOST, # "127.0.0.1
application_1: MyMaster = MyMaster(HOST=HOST, # "127.0.0.1
LOCAL="0.0.0.0",
PORT=int(PORT),
DNP3_ADDR=int(DNP3_ADDR),
Expand All @@ -82,11 +106,26 @@ def run_master(device_ip_port_config_all_13bus, names,simulation_id,gapps,dnp3_t
listener=AppChannelListener(),
soe_handler=SOEHandler(object_name, convertion_type, dnp3_to_cim,gapps),
master_application=MasterApplication())
application_1.name=name
# TODO: kefei comment: (from dnp3.master_pnnl import MyMaster) MyMaster doesn't have def start method. How is it going to start?
master_application = MyMasterNew(port=40000)
master_application.start()
# master_ip=d_args.get("master_ip="),
# outstation_ip=d_args.get("outstation_ip="),
# port=d_args.get("port="),
# master_id=d_args.get("master_id="),
# outstation_id=d_args.get("outstation_id="),

# # channel_log_level=opendnp3.levels.ALL_COMMS,
# # master_log_level=opendnp3.levels.ALL_COMMS
# # soe_handler=SOEHandler(soehandler_log_level=logging.DEBUG)
# )
# master_application = MyMasterNew()
application_1.name=name # TODO: check if this is valid
# application.channel.SetLogFilters(openpal.LogFilters(opendnp3.levels.ALL_COMMS))
_log.debug('Channel log filtering level is now: {0}'.format(opendnp3.levels.ALL_COMMS))

masters.append(application_1)
# masters.append(application_1)
masters.append(master_application)

pv_points = []
for key in conversion_dict:
Expand All @@ -108,7 +147,8 @@ def run_master(device_ip_port_config_all_13bus, names,simulation_id,gapps,dnp3_t

myCIMProcessor = CIMProcessor(pv_points,application_1)

gapps.subscribe('/topic/goss.gridappsd.field.input', on_message)
# gapps.subscribe('/topic/goss.gridappsd.field.input', on_message)
gapps.subscribe(topics.field_input_topic(), on_message)

SLEEP_SECONDS = 1
time.sleep(SLEEP_SECONDS)
Expand All @@ -119,17 +159,98 @@ def run_master(device_ip_port_config_all_13bus, names,simulation_id,gapps,dnp3_t

msg_count=0
csv_dict = {}
cim_full_msg = {'simulation_id': simulation_id, 'message':{'timestamp': int(time.time()),'measurements':{}}}
cim_full_msg = {'message':{'timestamp': int(time.time()),'measurements':{}}}





# while True:
# current_time = time.time()
# for master in masters:
# master.send_scan_all_request()
# # master_soe_handler: SOEHandler = master.soe_handler
# # cim_msg = master_soe_handler.get_msg()
# cim_msg = master.soe_handler.db # TODO: note this is place where cim_msg should be formatted
# # cim_msg = master.master_application.get_config()
# cim_full_msg['message']['measurements'].update(cim_msg)
# cim_full_msg['message']['timestamp'] = str(int(current_time))
# _log.debug(f'Publishing CIM measurement: {json.dumps(cim_full_msg)}')
# # gapps.send('/topic/goss.gridappsd.field.output', json.dumps(cim_full_msg))
# gapps.send(topics.field_output_topic(), json.dumps(cim_full_msg))
# logger.info(f"{cim_full_msg=}") # TODO: kefei added
# msg_count+=1
# time.sleep(2)

# """ # example message: https://gridappsd.readthedocs.io/en/master/using_gridappsd/index.html?highlight=cim#subscribe-to-simulation-output
{
"simulation_id" : "12ae2345",
"message" : {
"timestamp" : "1357048800",
"measurements" : {
"123a456b-789c-012d-345e-678f901a234b":{
"measurement_mrid" : "123a456b-789c-012d-345e-678f901a234b",
"value": 1
# "magnitude" : 3410.456,
# "angle" : -123.456
}
}
}
}


# in /home/shared_user/gridappsd-dnp3-master/dnp3-master/service/config/new_measurement_dict_master.json
new_measurement_dict_master = {
"ufls_59.1": {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be better if python files do not have a specific model dependent dictionaries. Make that configurable based on input.

"Pos": {
"ABC": [
{
"mrid": "1d88371e-3db5-4b23-b8cd-fc0f2f3569fb",
"type": "value"
}
]
}
},
"ufls_59.5": {
"Pos": {
"ABC": [
{
"mrid": "a9eb2b35-c340-4d31-9a0a-4ff2d4463361",
"type": "value"
}
]
}
}
}

def register_mapping(register_name: str, db_data):
"""# mapping based on register name, e.g., ufls_59.1" -> "BinaryOutputStatus"[0]"""
if register_name == "ufls_59.1":
return db_data["BinaryOutputStatus"][0]
else:
return db_data["BinaryOutputStatus"][1]

while True:
current_time = time.time()
for master in masters:
cim_msg = master.soe_handler.get_msg()
cim_full_msg['message']['measurements'].update(cim_msg)
for k, v in new_measurement_dict_master.items():
master_application.send_scan_all_request()
# master_soe_handler: SOEHandler = master.soe_handler
# cim_msg = master_soe_handler.get_msg()
db_data = master_application.soe_handler.db
mr_id = v["Pos"]["ABC"][0]["mrid"]
value = register_mapping(k, db_data)
value=1 if value else 0 # convert to 1 or 0 (originally True or False)
cim_full_msg['message']['timestamp'] = str(int(current_time))
_log.debug(f'Publishing CIM measurement: {json.dumps(cim_full_msg)}')
gapps.send('/topic/goss.gridappsd.field.output', json.dumps(cim_full_msg))

cim_full_msg['message']['measurements'] = {
mr_id:{
"measurement_mrid" : mr_id,
"value": value
}}
_log.debug(f'Publishing CIM measurement XXXX: {json.dumps(cim_full_msg)}')
# _log.debug(f"{master_application.soe_handler.db=}")
# gapps.send('/topic/goss.gridappsd.field.output', json.dumps(cim_full_msg))
gapps.send(topics.field_output_topic(), json.dumps(cim_full_msg))
# logger.info(f"{cim_full_msg=}") # TODO: kefei added
msg_count+=1
time.sleep(2)

Expand Down