#!/usr/bin/env python """ Apply MPS Configuration patch file Example patch file:: { "version": 1, "devices": [ [30, 12, 1, "BLM:UND1:4:LOSS_L", "THRESHOLD", "IS_EXCEEDED", "IS_OK", false, "Immediate low threshold"], [30, 12, 2, "BLM:UND1:4:LOSS_H", "THRESHOLD", "IS_EXCEEDED", "IS_OK", false, "Immediate high threshold"], [30, 12, 3, "BLM:UND1:4:LOSS_1_L", "THRESHOLD", "IS_EXCEEDED", "IS_OK", false, "1 Hz low threshold"], [30, 12, 4, "BLM:UND1:4:LOSS_1_H", "THRESHOLD", "IS_EXCEEDED", "IS_OK", false, "1 Hz high threshold"], [30, 12, 5, "BLM:UND1:4:LOSS_10_L", "THRESHOLD", "IS_EXCEEDED", "IS_OK", false, "10 Hz low threshold"], [30, 12, 6, "BLM:UND1:4:LOSS_10_H", "THRESHOLD", "IS_EXCEEDED", "IS_OK", false, "10 Hz high threshold"], [30, 12, 7, "BLM:UND1:4:LOSS_30_L", "THRESHOLD", "IS_EXCEEDED", "IS_OK", false, "30 Hz low threshold"], [30, 12, 8, "BLM:UND1:4:LOSS_30_H", "THRESHOLD", "IS_EXCEEDED", "IS_OK", false, "30 Hz high threshold"], [39, 3, 10, "XPP:NH3:POS_00:IN", "POSITION", "IS_NOT_IN", "IS_IN", true, ""], [39, 3, 11, "HX3:UVD:VGC_01:CLS_DI", "POSITION", "IS_NOT_CLOSED", "IS_CLOSED", true, "Close switch"], [39, 3, 12, "HX3:UVD:VGC_01:OPN_DI", "POSITION", "IS_NOT_OPEN", "IS_OPEN", true, "Open switch"], [39, 3, 13, "HX3:DVD:VGC_01:CLS_DI", "POSITION", "IS_NOT_CLOSED", "IS_CLOSED", true, ""], [39, 3, 14, "HX3:DVD:VGC_01:OPN_DI", "POSITION", "IS_NOT_OPEN", "IS_OPEN", true, ""] ], "pics": [ [11, 1, 4, "IN20", "185"], [11, 1, 5, "IN20", "232"], [11, 1, 6, "IN20", "245"], [16, 1, 1, "LI24", "791"], [16, 1, 2, "LI24", "811"], [22, 1, 4, "LI29", "546"] ], "external_pvs": [ ["MPS:MCC0:LION716:STATE", "STATE", "IS_OK", "IS_FAULTED", true, ""], ["QUAD:LTU1:860:STATE", "STATE", "IS_OK", "IS_FAULTED", true, ""], ["MPS:MCC0:LION505:STATE", "STATE", "IS_OK", "IS_FAULTED", true, ""], ["MPS:MCC0:2:PICBLM_WD", "STATE", "IS_OK", "IS_FAULTED", true, ""], ["MPS:MCC0:PIC997:STATE", "STATE", "IS_OK", "IS_FAULTED", true, ""], ["QUAD:LTU1:840:INTOL", "STATE", "IS_OK", "IS_FAULTED", true, ""] ] } Where device data order is: 0) Link Node ID 1) Card Number * 1-6 for digital input cards * 7-8 for virtual input cards * 9-17 for BLM input cards (8 BLM cards, 1 BLM HVPS card) * 9-40 for PIC input cards 2) Channel (1-16) 3) Full PV 4) Fault Name 5) Faulted State String 6) OK State String 7) Autorecoverable (false/true) 8) Fault description PIC data order is: 0) Link Node ID 1) PIC Transition Card Number (1-4) 2) PIC Channel (1-8) 3) PV Area 4) PV Position And External PV data order is: 0) External PV 1) Fault Name 2) Faulted State String 3) OK State String 4) Autorecoverable (false/true) 5) Fault description """ import sys import sqlite3 import argparse import json import mpsconfig __author__ = 'Stephen Norum ' __version__ = '1.0.5' class Pic(object): channels = ( ( 1, 'LOSSL'), ( 2, 'LOSSH'), ( 3, 'LOSS1L'), ( 4, 'LOSS1H'), ( 5, 'LOSS10L'), ( 6, 'LOSS10H'), ( 7, 'LOSS30L'), ( 8, 'LOSS30H'), ( 9, 'LOSS60L'), (10, 'LOSS60H') ) def __init__(self, lnid, transition_card, channel, pvarea, pvpos, pvdevtype='PICM'): self.lnid = lnid self.transition_card = transition_card self.channel = channel self.pvdevtype = pvdevtype self.pvarea = pvarea self.pvpos = pvpos @property def card(self): return (self.transition_card - 1) * 8 + self.channel + 8 @property def fault_list(self): fault_list = [] for chan_number, chan_name in Pic.channels: f = mpsconfig.insert.FaultInput( self.lnid, self.card, chan_number, self.pvdevtype, self.pvarea, self.pvpos, chan_name, faultname = 'THRESHOLD', faultedname = 'IS_EXCEEDED', okname='IS_OK', autorecoverable=False, ) fault_list.append(f) return fault_list def create_fault_from_device_values(device_values): keys = ('lnid', 'card', 'channel', 'fullpv', 'faultname', 'faultedname', 'okname', 'autorecoverable', 'description') device_dict = dict(zip(keys, device_values)) (pvdevtype, pvarea, pvpos, pvattr) = device_dict['fullpv'].split(':') f = mpsconfig.insert.FaultInput( device_dict['lnid'], device_dict['card'], device_dict['channel'], pvdevtype, pvarea, pvpos, pvattr, faultname=device_dict['faultname'], faultedname=device_dict['faultedname'], okname=device_dict['okname'], autorecoverable=device_dict['autorecoverable'], description=device_dict['description'] ) return f def create_pics_from_pic_values(pic_values): keys = ('lnid', 'pic_transition_card', 'pic_channel', 'pvarea', 'pvpos') info = dict(zip(keys, pic_values)) p = Pic( info['lnid'], info['pic_transition_card'], info['pic_channel'], info['pvarea'], info['pvpos'] ) return p def process_arguments(argv=None): if argv is None: argv = sys.argv[1:] parser = argparse.ArgumentParser() parser.add_argument('mps_file_path', metavar='MPS_CONFIG_FILE', help='.mps file') parser.add_argument('patch_file_path', metavar='PATCH_FILE', help='patch file') parser.add_argument('-n', '--dry-run', action='store_true', help='show patch actions without actually applying them') args = parser.parse_args(argv) return args def main(argv=None): if argv is None: argv = sys.argv[1:] args = process_arguments(argv) with open(args.patch_file_path) as f: try: patch = json.load(f) except (ValueError) as e: print e return 1 # Create device faults faults = [create_fault_from_device_values(device_values) for device_values in patch.get('devices', [])] # Create PIC faults, extending device faults pics = [create_pics_from_pic_values(pic_values) for pic_values in patch.get('pics', [])] for pic in pics: faults.extend(pic.fault_list) # Show all fault information for fault in faults: print str(fault) print print print # Apply patch connection = sqlite3.connect(args.mps_file_path) connection.row_factory = sqlite3.Row cursor = connection.cursor() mpsconfig.insert.insert_fault_inputs(cursor, faults, True) if args.dry_run: connection.rollback() print '** Dry Run. Patch not applied. **' else: connection.commit() connection.close() return 0 if __name__ == '__main__': status = main() sys.exit(status)