diff --git a/Modbus Map.xlsx b/Modbus Map.xlsx new file mode 100644 index 0000000..6b20116 Binary files /dev/null and b/Modbus Map.xlsx differ diff --git a/README.md b/README.md new file mode 100644 index 0000000..3fc29e0 --- /dev/null +++ b/README.md @@ -0,0 +1,6 @@ +# Modbus Register Map + +## Coils + +Reg. # | Description | Access | +1 | diff --git a/analog.json b/analog.json new file mode 100644 index 0000000..1864a69 --- /dev/null +++ b/analog.json @@ -0,0 +1,149 @@ +[ + {"tag_name": "_Firmware_Rev", "register_type": "ir", "register_number": 1, "scale_type": 0, "scale_multiplier": 1}, + {"tag_name": "_Program_Firmware", "register_type": "ir", "register_number": 6, "scale_type": 0, "scale_multiplier": 1}, + {"tag_name": "Card_Past[1].Card_Type", "register_type": "ir", "register_number": 11, "scale_type": 0, "scale_multiplier": 1}, + {"tag_name": "Card_Past[1].Downhole_AdjustedGrossStroke", "register_type": "ir", "register_number": 16, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[1].Downhole_FluidLoad", "register_type": "ir", "register_number": 21, "scale_type": 0, "scale_multiplier": 1}, + {"tag_name": "Card_Past[1].Downhole_GrossStroke", "register_type": "ir", "register_number": 26, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[1].Downhole_Max_Load.Load", "register_type": "ir", "register_number": 31, "scale_type": 0, "scale_multiplier": 1}, + {"tag_name": "Card_Past[1].Downhole_Max_Position.Position", "register_type": "ir", "register_number": 36, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[1].Downhole_Min_Load.Load", "register_type": "ir", "register_number": 41, "scale_type": 0, "scale_multiplier": 1}, + {"tag_name": "Card_Past[1].Downhole_Min_Position.Position", "register_type": "ir", "register_number": 46, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[1].Downhole_NetStroke", "register_type": "ir", "register_number": 51, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[1].Fillage_Percent", "register_type": "ir", "register_number": 56, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[1].Fluid_Above_Pump", "register_type": "ir", "register_number": 61, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[1].Fluid_Moved", "register_type": "ir", "register_number": 66, "scale_type": 0, "scale_multiplier": 10000}, + {"tag_name": "Card_Past[1].ID", "register_type": "ir", "register_number": 71, "scale_type": 0, "scale_multiplier": 1}, + {"tag_name": "Card_Past[1].Num_Points", "register_type": "ir", "register_number": 76, "scale_type": 0, "scale_multiplier": 1}, + {"tag_name": "Card_Past[1].Polished_Rod_HP", "register_type": "ir", "register_number": 81, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[1].Pump_HP", "register_type": "ir", "register_number": 86, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[1].Pump_Intake_Pressure", "register_type": "ir", "register_number": 91, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[1].SPM", "register_type": "ir", "register_number": 96, "scale_type": 0, "scale_multiplier": 1000}, + {"tag_name": "Card_Past[1].Surface_Max.Load", "register_type": "ir", "register_number": 101, "scale_type": 0, "scale_multiplier": 1}, + {"tag_name": "Card_Past[1].Surface_Max.Position", "register_type": "ir", "register_number": 106, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[1].Surface_Min.Load", "register_type": "ir", "register_number": 111, "scale_type": 0, "scale_multiplier": 1}, + {"tag_name": "Card_Past[1].Surface_Min.Position", "register_type": "ir", "register_number": 116, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[1].Surface_StrokeLength", "register_type": "ir", "register_number": 121, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[1].Tubing_Movement", "register_type": "ir", "register_number": 126, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[2].Card_Type", "register_type": "ir", "register_number": 131, "scale_type": 0, "scale_multiplier": 1}, + {"tag_name": "Card_Past[2].Downhole_AdjustedGrossStroke", "register_type": "ir", "register_number": 136, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[2].Downhole_FluidLoad", "register_type": "ir", "register_number": 141, "scale_type": 0, "scale_multiplier": 1}, + {"tag_name": "Card_Past[2].Downhole_GrossStroke", "register_type": "ir", "register_number": 146, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[2].Downhole_Max_Load.Load", "register_type": "ir", "register_number": 151, "scale_type": 0, "scale_multiplier": 1}, + {"tag_name": "Card_Past[2].Downhole_Max_Position.Position", "register_type": "ir", "register_number": 156, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[2].Downhole_Min_Load.Load", "register_type": "ir", "register_number": 161, "scale_type": 0, "scale_multiplier": 1}, + {"tag_name": "Card_Past[2].Downhole_Min_Position.Position", "register_type": "ir", "register_number": 166, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[2].Downhole_NetStroke", "register_type": "ir", "register_number": 171, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[2].Fillage_Percent", "register_type": "ir", "register_number": 176, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[2].Fluid_Above_Pump", "register_type": "ir", "register_number": 181, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[2].Fluid_Moved", "register_type": "ir", "register_number": 186, "scale_type": 0, "scale_multiplier": 10000}, + {"tag_name": "Card_Past[2].ID", "register_type": "ir", "register_number": 191, "scale_type": 0, "scale_multiplier": 1}, + {"tag_name": "Card_Past[2].Num_Points", "register_type": "ir", "register_number": 196, "scale_type": 0, "scale_multiplier": 1}, + {"tag_name": "Card_Past[2].Polished_Rod_HP", "register_type": "ir", "register_number": 201, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[2].Pump_HP", "register_type": "ir", "register_number": 206, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[2].Pump_Intake_Pressure", "register_type": "ir", "register_number": 211, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[2].SPM", "register_type": "ir", "register_number": 216, "scale_type": 0, "scale_multiplier": 1000}, + {"tag_name": "Card_Past[2].Surface_Max.Load", "register_type": "ir", "register_number": 221, "scale_type": 0, "scale_multiplier": 1}, + {"tag_name": "Card_Past[2].Surface_Max.Position", "register_type": "ir", "register_number": 226, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[2].Surface_Min.Load", "register_type": "ir", "register_number": 231, "scale_type": 0, "scale_multiplier": 1}, + {"tag_name": "Card_Past[2].Surface_Min.Position", "register_type": "ir", "register_number": 236, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[2].Surface_StrokeLength", "register_type": "ir", "register_number": 241, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[2].Tubing_Movement", "register_type": "ir", "register_number": 246, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[3].Card_Type", "register_type": "ir", "register_number": 251, "scale_type": 0, "scale_multiplier": 1}, + {"tag_name": "Card_Past[3].Downhole_AdjustedGrossStroke", "register_type": "ir", "register_number": 256, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[3].Downhole_FluidLoad", "register_type": "ir", "register_number": 261, "scale_type": 0, "scale_multiplier": 1}, + {"tag_name": "Card_Past[3].Downhole_GrossStroke", "register_type": "ir", "register_number": 266, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[3].Downhole_Max_Load.Load", "register_type": "ir", "register_number": 271, "scale_type": 0, "scale_multiplier": 1}, + {"tag_name": "Card_Past[3].Downhole_Max_Position.Position", "register_type": "ir", "register_number": 276, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[3].Downhole_Min_Load.Load", "register_type": "ir", "register_number": 281, "scale_type": 0, "scale_multiplier": 1}, + {"tag_name": "Card_Past[3].Downhole_Min_Position.Position", "register_type": "ir", "register_number": 286, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[3].Downhole_NetStroke", "register_type": "ir", "register_number": 291, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[3].Fillage_Percent", "register_type": "ir", "register_number": 296, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[3].Fluid_Above_Pump", "register_type": "ir", "register_number": 301, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[3].Fluid_Moved", "register_type": "ir", "register_number": 306, "scale_type": 0, "scale_multiplier": 10000}, + {"tag_name": "Card_Past[3].ID", "register_type": "ir", "register_number": 311, "scale_type": 0, "scale_multiplier": 1}, + {"tag_name": "Card_Past[3].Num_Points", "register_type": "ir", "register_number": 316, "scale_type": 0, "scale_multiplier": 1}, + {"tag_name": "Card_Past[3].Polished_Rod_HP", "register_type": "ir", "register_number": 321, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[3].Pump_HP", "register_type": "ir", "register_number": 326, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[3].Pump_Intake_Pressure", "register_type": "ir", "register_number": 331, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[3].SPM", "register_type": "ir", "register_number": 336, "scale_type": 0, "scale_multiplier": 1000}, + {"tag_name": "Card_Past[3].Surface_Max.Load", "register_type": "ir", "register_number": 341, "scale_type": 0, "scale_multiplier": 1}, + {"tag_name": "Card_Past[3].Surface_Max.Position", "register_type": "ir", "register_number": 346, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[3].Surface_Min.Load", "register_type": "ir", "register_number": 351, "scale_type": 0, "scale_multiplier": 1}, + {"tag_name": "Card_Past[3].Surface_Min.Position", "register_type": "ir", "register_number": 356, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[3].Surface_StrokeLength", "register_type": "ir", "register_number": 361, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[3].Tubing_Movement", "register_type": "ir", "register_number": 366, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[4].Card_Type", "register_type": "ir", "register_number": 371, "scale_type": 0, "scale_multiplier": 1}, + {"tag_name": "Card_Past[4].Downhole_AdjustedGrossStroke", "register_type": "ir", "register_number": 376, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[4].Downhole_FluidLoad", "register_type": "ir", "register_number": 381, "scale_type": 0, "scale_multiplier": 1}, + {"tag_name": "Card_Past[4].Downhole_GrossStroke", "register_type": "ir", "register_number": 386, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[4].Downhole_Max_Load.Load", "register_type": "ir", "register_number": 391, "scale_type": 0, "scale_multiplier": 1}, + {"tag_name": "Card_Past[4].Downhole_Max_Position.Position", "register_type": "ir", "register_number": 396, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[4].Downhole_Min_Load.Load", "register_type": "ir", "register_number": 401, "scale_type": 0, "scale_multiplier": 1}, + {"tag_name": "Card_Past[4].Downhole_Min_Position.Position", "register_type": "ir", "register_number": 406, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[4].Downhole_NetStroke", "register_type": "ir", "register_number": 411, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[4].Fillage_Percent", "register_type": "ir", "register_number": 416, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[4].Fluid_Above_Pump", "register_type": "ir", "register_number": 421, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[4].Fluid_Moved", "register_type": "ir", "register_number": 426, "scale_type": 0, "scale_multiplier": 10000}, + {"tag_name": "Card_Past[4].ID", "register_type": "ir", "register_number": 431, "scale_type": 0, "scale_multiplier": 1}, + {"tag_name": "Card_Past[4].Num_Points", "register_type": "ir", "register_number": 436, "scale_type": 0, "scale_multiplier": 1}, + {"tag_name": "Card_Past[4].Polished_Rod_HP", "register_type": "ir", "register_number": 441, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[4].Pump_HP", "register_type": "ir", "register_number": 446, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[4].Pump_Intake_Pressure", "register_type": "ir", "register_number": 451, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[4].SPM", "register_type": "ir", "register_number": 456, "scale_type": 0, "scale_multiplier": 1000}, + {"tag_name": "Card_Past[4].Surface_Max.Load", "register_type": "ir", "register_number": 461, "scale_type": 0, "scale_multiplier": 1}, + {"tag_name": "Card_Past[4].Surface_Max.Position", "register_type": "ir", "register_number": 466, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[4].Surface_Min.Load", "register_type": "ir", "register_number": 471, "scale_type": 0, "scale_multiplier": 1}, + {"tag_name": "Card_Past[4].Surface_Min.Position", "register_type": "ir", "register_number": 476, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[4].Surface_StrokeLength", "register_type": "ir", "register_number": 481, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Card_Past[4].Tubing_Movement", "register_type": "ir", "register_number": 486, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Drive_Speed_Reference_SP", "register_type": "ir", "register_number": 491, "scale_type": 0, "scale_multiplier": 10}, + {"tag_name": "Drive_Torque_Percent", "register_type": "ir", "register_number": 496, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "GAUGEOFF_Average_SPM", "register_type": "ir", "register_number": 501, "scale_type": 0, "scale_multiplier": 1000}, + {"tag_name": "GAUGEOFF_Downhole_GrossStroke", "register_type": "ir", "register_number": 506, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "GAUGEOFF_Downhole_NetStroke", "register_type": "ir", "register_number": 511, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "GAUGEOFF_Electricity_Cost", "register_type": "ir", "register_number": 516, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "GAUGEOFF_Fluid_Above_Pump", "register_type": "ir", "register_number": 521, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "GAUGEOFF_Inflow_Rate", "register_type": "ir", "register_number": 526, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "GAUGEOFF_kWh", "register_type": "ir", "register_number": 531, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "GAUGEOFF_kWh_Regen", "register_type": "ir", "register_number": 536, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "GAUGEOFF_Lifting_Cost", "register_type": "ir", "register_number": 541, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "GAUGEOFF_Max_Load", "register_type": "ir", "register_number": 546, "scale_type": 0, "scale_multiplier": 1}, + {"tag_name": "GAUGEOFF_Min_Load", "register_type": "ir", "register_number": 551, "scale_type": 0, "scale_multiplier": 1}, + {"tag_name": "GAUGEOFF_Percent_Run", "register_type": "ir", "register_number": 556, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "GAUGEOFF_Polished_Rod_HP", "register_type": "ir", "register_number": 561, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "GAUGEOFF_Pump_Intake_Pressure", "register_type": "ir", "register_number": 566, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "GAUGEOFF_Surface_StrokeLength", "register_type": "ir", "register_number": 571, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "GAUGEOFF_Tubing_Movement", "register_type": "ir", "register_number": 576, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Gearbox_Loading", "register_type": "ir", "register_number": 581, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Gearbox_Torque", "register_type": "ir", "register_number": 586, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Input_Analog_1_AIN.Val", "register_type": "ir", "register_number": 591, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Input_Analog_2_AIN.Val", "register_type": "ir", "register_number": 596, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Input_Analog_3_AIN.Val", "register_type": "ir", "register_number": 601, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Instantaneous_SPM", "register_type": "ir", "register_number": 606, "scale_type": 0, "scale_multiplier": 10}, + {"tag_name": "kWh_Today", "register_type": "ir", "register_number": 611, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Max_Theoretical_Fluid_Load", "register_type": "ir", "register_number": 616, "scale_type": 0, "scale_multiplier": 1}, + {"tag_name": "Motor_Torque", "register_type": "ir", "register_number": 621, "scale_type": 0, "scale_multiplier": 100}, + + {"tag_name": "_dt", "register_type": "hr", "register_number": 1, "scale_type": 0, "scale_multiplier": 1000}, + {"tag_name": "Casing_ID", "register_type": "hr", "register_number": 6, "scale_type": 0, "scale_multiplier": 1000}, + {"tag_name": "Drive_Start_Speed", "register_type": "hr", "register_number": 11, "scale_type": 0, "scale_multiplier": 10}, + {"tag_name": "Electricity_Cost", "register_type": "hr", "register_number": 16, "scale_type": 0, "scale_multiplier": 1000}, + {"tag_name": "Estimated_Tubing_Movement", "register_type": "hr", "register_number": 21, "scale_type": 0, "scale_multiplier": 100}, + {"tag_name": "Fluid_Gradient", "register_type": "hr", "register_number": 26, "scale_type": 0, "scale_multiplier": 1000}, + {"tag_name": "Friction", "register_type": "hr", "register_number": 31, "scale_type": 0, "scale_multiplier": 10}, + {"tag_name": "Gauge_Off_Time.Hour", "register_type": "hr", "register_number": 36, "scale_type": 0, "scale_multiplier": 1}, + {"tag_name": "Gauge_Off_Time.Min", "register_type": "hr", "register_number": 41, "scale_type": 0, "scale_multiplier": 1}, + {"tag_name": "Input_Analog_1_AIN.Cfg_PVEUMax", "register_type": "hr", "register_number": 46, "scale_type": 0, "scale_multiplier": 1}, + {"tag_name": "Input_Analog_1_AIN.Cfg_PVEUMin", "register_type": "hr", "register_number": 51, "scale_type": 0, "scale_multiplier": 1}, + {"tag_name": "Input_Analog_2_AIN.Cfg_PVEUMax", "register_type": "hr", "register_number": 56, "scale_type": 0, "scale_multiplier": 1}, + {"tag_name": "Input_Analog_2_AIN.Cfg_PVEUMin", "register_type": "hr", "register_number": 61, "scale_type": 0, "scale_multiplier": 1}, + {"tag_name": "Input_Analog_3_AIN.Cfg_PVEUMax", "register_type": "hr", "register_number": 66, "scale_type": 0, "scale_multiplier": 1}, + {"tag_name": "Input_Analog_3_AIN.Cfg_PVEUMin", "register_type": "hr", "register_number": 71, "scale_type": 0, "scale_multiplier": 1}, + {"tag_name": "Input_Inclinometer_AIN.Cfg_PVEUMax", "register_type": "hr", "register_number": 76, "scale_type": 0, "scale_multiplier": 1}, + {"tag_name": "Input_Inclinometer_AIN.Cfg_PVEUMin", "register_type": "hr", "register_number": 81, "scale_type": 0, "scale_multiplier": 1}, + {"tag_name": "Input_LoadCell_AIN.Cfg_PVEUMax", "register_type": "hr", "register_number": 86, "scale_type": 0, "scale_multiplier": 1}, + {"tag_name": "Input_LoadCell_AIN.Cfg_PVEUMin", "register_type": "hr", "register_number": 91, "scale_type": 0, "scale_multiplier": 1}, + {"tag_name": "K_Factor", "register_type": "hr", "register_number": 96, "scale_type": 0, "scale_multiplier": 1000}, + {"tag_name": "Min_Fluid_Load_Shutdown_Setpoint", "register_type": "hr", "register_number": 101, "scale_type": 0, "scale_multiplier": 1} +] diff --git a/arraylist.json b/arraylist.json new file mode 100644 index 0000000..221a9a5 --- /dev/null +++ b/arraylist.json @@ -0,0 +1,4 @@ + +[ + +] diff --git a/digital.json b/digital.json new file mode 100644 index 0000000..3d1232d --- /dev/null +++ b/digital.json @@ -0,0 +1,31 @@ +[ + {"tag_name": "_TOC_ACCEPTED", "register_type": "co", "register_number": 1}, + {"tag_name": "Autotune_Next_Start", "register_type": "co", "register_number": 2}, + {"tag_name": "Gas_Interference_Override_Enabled", "register_type": "co", "register_number": 3}, + {"tag_name": "Gauge_Off_Manual", "register_type": "co", "register_number": 4}, + {"tag_name": "Initialize", "register_type": "co", "register_number": 5}, + {"tag_name": "Input_Analog_1.Channel", "register_type": "co", "register_number": 6}, + {"tag_name": "Input_Analog_1.Enabled", "register_type": "co", "register_number": 7}, + {"tag_name": "Input_Analog_1.Type", "register_type": "co", "register_number": 8}, + {"tag_name": "Input_Analog_2.Channel", "register_type": "co", "register_number": 9}, + {"tag_name": "Input_Analog_2.Enabled", "register_type": "co", "register_number": 10}, + {"tag_name": "Input_Analog_2.Type", "register_type": "co", "register_number": 11}, + {"tag_name": "Input_Analog_3.Channel", "register_type": "co", "register_number": 12}, + {"tag_name": "Input_Analog_3.Enabled", "register_type": "co", "register_number": 13}, + {"tag_name": "Input_Analog_3.Type", "register_type": "co", "register_number": 14}, + {"tag_name": "Input_Inclinometer_Calibrate", "register_type": "co", "register_number": 15}, + {"tag_name": "Input_Inclinometer.Channel", "register_type": "co", "register_number": 16}, + {"tag_name": "Input_Inclinometer.Enabled", "register_type": "co", "register_number": 17}, + {"tag_name": "Input_Inclinometer.Type", "register_type": "co", "register_number": 18}, + {"tag_name": "Input_LoadCell.Channel", "register_type": "co", "register_number": 19}, + {"tag_name": "Input_LoadCell.Enabled", "register_type": "co", "register_number": 20}, + {"tag_name": "Input_LoadCell.Type", "register_type": "co", "register_number": 21}, + {"tag_name": "Min_Fluid_Load_Shutdown_Enabled", "register_type": "co", "register_number": 22}, + {"tag_name": "Restart_After_Fault_Allowed", "register_type": "co", "register_number": 23}, + {"tag_name": "Update_Tapers", "register_type": "co", "register_number": 24}, + {"tag_name": "USE_WIRELESS_LOADCELL", "register_type": "co", "register_number": 25}, + {"tag_name": "Write_Mode_Data", "register_type": "co", "register_number": 26}, + {"tag_name": "Write_Setup_Data", "register_type": "co", "register_number": 27}, + {"tag_name": "Inclinometer_Calibrating", "register_type": "di", "register_number": 1}, + {"tag_name": "Inclinometer_Stale", "register_type": "di", "register_number": 2} +] diff --git a/plc_to_mongo.py b/plc_to_mongo.py new file mode 100644 index 0000000..8b5ad50 --- /dev/null +++ b/plc_to_mongo.py @@ -0,0 +1,90 @@ +import pymongo +import json +from time import sleep +from time import time as now +from pymongo import MongoClient +import pycomm_helper.utils as plc + +PLC_IP_ADDRESS = '10.20.4.7' + + +def main(): + client = MongoClient() + db = client.tag_data + + tag_vals = db.tag_vals + print("THERE ARE ALREADY {} VALUES IN tag_vals".format(tag_vals.count())) + with open('analog.json', 'rb') as analogfile: + analog_list = json.loads(analogfile.read()) + + with open('digital.json', 'rb') as digitalfile: + digital_list = json.loads(digitalfile.read()) + + with open('arraylist.json', 'rb') as arrayfile: + arr_list = [] # json.loads(arrayfile.read()) + + for entry in analog_list + digital_list + arr_list: + if tag_vals.find({'tag_name': entry['tag_name']}).count() < 1: + tag_vals.insert(entry) + print("NOW THERE ARE {} VALUES IN tag_vals".format(tag_vals.count())) + + while True: + for t in analog_list: + try: + plc_val = plc.readTag(PLC_IP_ADDRESS, t['tag_name']) + if plc_val: + t['tag_type'] = plc_val[1] + t['val_actual'] = plc_val[0] + t['timestamp'] = now() + if int(t['scale_type']) == 0: + t['val'] = int(plc_val[0] * t['scale_multiplier']) + else: + t['val'] = int(plc_val[0] / t['scale_multiplier']) + tag_vals.update({'tag_name': t['tag_name']}, t) + print("Updated: {}".format(tag_vals.find({'tag_name': t['tag_name']})[0])) + except Exception as e: + print("[ERROR] {} - {}".format(t['tag_name'], e)) + + for t in digital_list: + try: + plc_val = plc.readTag(PLC_IP_ADDRESS, t['tag_name']) + if plc_val: + t['tag_type'] = plc_val[1] + t['val'] = plc_val[0] + t['timestamp'] = now() + tag_vals.update({'tag_name': t['tag_name']}, t) + print("Updated: {}".format(tag_vals.find({'tag_name': t['tag_name']})[0])) + except Exception as e: + print("[ERROR] {} - {}".format(t['tag_name'], e)) + + for a in arr_list: + try: + plc_val = plc.readArray(PLC_IP_ADDRESS, str(a['tag_name']), int(a['length'])) + if plc_val: + a['val'] = plc_val + a['tag_type'] = 'ARRAY' + t['timestamp'] = now() + tag_vals.update({'tag_name': a['tag_name']}, a) + print("Updated: {}".format(tag_vals.find({'tag_name': a['tag_name']})[0])) + except Exception as e: + print("[ERROR] {} - {}".format(a['tag_name'], e)) + + sleep(5) + + +def purge(): + client = MongoClient() + db = client.tag_data + + tag_vals = db.tag_vals + tag_vals.delete_many({}) + print("THERE ARE {} VALUES IN tag_vals".format(tag_vals.count())) + +if __name__ == '__main__': + import sys + if len(sys.argv) > 1: + if sys.argv[1] == 'purge': + print("Purging...") + purge() + else: + main() diff --git a/poc-to-modbus.py b/poc-to-modbus.py deleted file mode 100644 index 46a35d7..0000000 --- a/poc-to-modbus.py +++ /dev/null @@ -1,85 +0,0 @@ -#!/usr/bin/env python3 -''' -Pymodbus Server With Updating Thread --------------------------------------------------------------------------- - -This is an example of having a background thread updating the -context while the server is operating. This can also be done with -a python thread:: - - from threading import Thread - - thread = Thread(target=updating_writer, args=(context,)) - thread.start() -''' -# ---------------------------------------------------------------------------# -# import the modbus libraries we need -# ---------------------------------------------------------------------------# -from pymodbus.server.async import StartTcpServer -from pymodbus.device import ModbusDeviceIdentification -from pymodbus.datastore import ModbusSequentialDataBlock -from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext -# from pymodbus.transaction import ModbusRtuFramer, ModbusAsciiFramer - -# ---------------------------------------------------------------------------# -# import the twisted libraries we need -# ---------------------------------------------------------------------------# -from twisted.internet.task import LoopingCall - -# ---------------------------------------------------------------------------# -# configure the service logging -# ---------------------------------------------------------------------------# -import logging -logging.basicConfig() -log = logging.getLogger() -log.setLevel(logging.DEBUG) - - -# ---------------------------------------------------------------------------# -# define your callback process -# ---------------------------------------------------------------------------# -def updating_writer(a): - ''' A worker process that runs every so often and - updates live values of the context. It should be noted - that there is a race condition for the update. - - :param arguments: The input arguments to the call - ''' - log.debug("updating the context") - context = a[0] - register = 3 - slave_id = 0x00 - address = 0x10 - values = context[slave_id].getValues(register, address, count=5) - values = [v + 1 for v in values] - log.debug("new values: " + str(values)) - context[slave_id].setValues(register, address, values) - -# ---------------------------------------------------------------------------# -# initialize your data store -# ---------------------------------------------------------------------------# -store = ModbusSlaveContext( - di=ModbusSequentialDataBlock(0, [17]*100), - co=ModbusSequentialDataBlock(0, [17]*100), - hr=ModbusSequentialDataBlock(0, [17]*100), - ir=ModbusSequentialDataBlock(0, [17]*100)) -context = ModbusServerContext(slaves=store, single=True) - -# ---------------------------------------------------------------------------# -# initialize the server information -# ---------------------------------------------------------------------------# -identity = ModbusDeviceIdentification() -identity.VendorName = 'pymodbus' -identity.ProductCode = 'PM' -identity.VendorUrl = 'http://github.com/bashwork/pymodbus/' -identity.ProductName = 'pymodbus Server' -identity.ModelName = 'pymodbus Server' -identity.MajorMinorRevision = '1.0' - -# ---------------------------------------------------------------------------# -# run the server you want -# ---------------------------------------------------------------------------# -time = 5 # 5 seconds delay -loop = LoopingCall(f=updating_writer, a=(context,)) -loop.start(time, now=False) # initially delay by time -StartTcpServer(context, identity=identity, address=("localhost", 5020)) diff --git a/poc_to_modbus.py b/poc_to_modbus.py new file mode 100644 index 0000000..a8aff9e --- /dev/null +++ b/poc_to_modbus.py @@ -0,0 +1,209 @@ +#!/usr/bin/env python +''' +Pymodbus Server With Callbacks +-------------------------------------------------------------------------- + +This is an example of adding callbacks to a running modbus server +when a value is written to it. In order for this to work, it needs +a device-mapping file. +''' +# ---------------------------------------------------------------------------# +# import the modbus libraries we need +# ---------------------------------------------------------------------------# +from pymodbus.server.async import StartTcpServer +from pymodbus.device import ModbusDeviceIdentification +from pymodbus.datastore import ModbusSparseDataBlock +from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext +from pymodbus.transaction import ModbusRtuFramer, ModbusAsciiFramer + +# ---------------------------------------------------------------------------# +# import the python libraries we need +# ---------------------------------------------------------------------------# +import pymongo +from pymongo import MongoClient +from pycomm_helper import utils as plc +from time import time as now +# ---------------------------------------------------------------------------# +# configure the service logging +# ---------------------------------------------------------------------------# +import logging +logging.basicConfig() +log = logging.getLogger() +log.setLevel(logging.DEBUG) + +PLC_IP_ADDRESS = '10.20.4.7' + + +def getTagsFromDB(): + client = MongoClient() + db = client.tag_data + tags = db.tag_vals + print("Found {} tags in the database".format(tags.count())) + di_tags_cur = tags.find({'register_type': 'di'}) + di_tags = list(di_tags_cur) + di_tags_num = di_tags_cur.count() + print("{} Digital Inputs".format(di_tags_num)) + + co_tags_cur = tags.find({'register_type': 'co'}) + co_tags = list(co_tags_cur) + co_tags_num = co_tags_cur.count() + print("{} Coils".format(co_tags_num)) + + ir_tags_cur = tags.find({'register_type': 'ir'}) + ir_tags = list(ir_tags_cur) + ir_tags_num = ir_tags_cur.count() + print("{} Input Registers".format(ir_tags_num)) + + hr_tags_cur = tags.find({'register_type': 'hr'}) + hr_tags = list(hr_tags_cur) + hr_tags_num = hr_tags_cur.count() + print("{} Holding Registers".format(hr_tags_num)) + + return {'di': di_tags, 'co': co_tags, 'ir': ir_tags, 'hr': hr_tags} + + +# ---------------------------------------------------------------------------# +# create your custom data block with callbacks +# ---------------------------------------------------------------------------# +class DigitalTagDataBlock(ModbusSparseDataBlock): + ''' A datablock that stores the new value in memory + and passes the operation to a message queue for further + processing. + ''' + + def __init__(self, register_type, tag_list): + ''' + ''' + values = {} + self.register_type = register_type + + for t in tag_list: + try: + values[t['register_number']] = t['val'] + except KeyError: + values[t['register_number']] = 911 + # print("Initialized DigitalTagDataBlock for {} with values {}".format(self.register_type, values)) + super(DigitalTagDataBlock, self).__init__(values) + + def getValues(self, address, count=1): + client = MongoClient() + db = client.tag_data + tags = db.tag_vals + + if count > 1: + for i in range(address, address + count): + tag_found = tags.find_one({'register_number': i, 'register_type': self.register_type}) + print("{} = {}".format(tag_found['tag_name'], tag_found['val'])) + super(DigitalTagDataBlock, self).setValues(address, tag_found['val']) + else: + tag_found = tags.find_one({'register_number': address, 'register_type': self.register_type}) + print("{} = {}".format(tag_found['tag_name'], tag_found['val'])) + super(DigitalTagDataBlock, self).setValues(address, tag_found['val']) + + return super(DigitalTagDataBlock, self).getValues(address, count=count) + + def setValues(self, address, value): + ''' Sets the requested values of the datastore + + :param address: The starting address + :param values: The new values to be set + ''' + client = MongoClient() + db = client.tag_data + tags = db.tag_vals + tag_name = tags.find_one({'register_number': address, 'register_type': self.register_type})['tag_name'] + plc.writeTag(PLC_IP_ADDRESS, tag_name, value) + + +class AnalogTagDataBlock(ModbusSparseDataBlock): + ''' A datablock that stores the new value in memory + and passes the operation to a message queue for further + processing. + ''' + + def __init__(self, register_type, tag_list): + ''' + ''' + values = {} + self.register_type = register_type + + for t in tag_list: + try: + values[t['register_number']] = t['val'] + values[t['register_number'] + 1] = t['scale_type'] + values[t['register_number'] + 2] = t['scale_multiplier'] + values[t['register_number'] + 3] = 0 + except KeyError: + values[t['register_number']] = 911 + values[t['register_number'] + 1] = 2 + values[t['register_number'] + 2] = 0 + values[t['register_number'] + 3] = 0 + values[t['register_number'] + 4] = 123 + + # print("Initialized AnalogTagDataBlock for {} with values {}".format(self.register_type, values)) + super(AnalogTagDataBlock, self).__init__(values) + + def getValues(self, address, count=1): + client = MongoClient() + db = client.tag_data + tags = db.tag_vals + + if count > 1: + for i in range(address, address + count): + tag_found = tags.find_one({'register_number': i, 'register_type': self.register_type}) + if tag_found: + print("{} = {}".format(tag_found['tag_name'], tag_found['val'])) + super(AnalogTagDataBlock, self).setValues(address, tag_found['val']) + super(AnalogTagDataBlock, self).setValues(address + 3, 0) + else: + tag_found = tags.find_one({'register_number': address, 'register_type': self.register_type}) + if tag_found: + print("{} = {}".format(tag_found['tag_name'], tag_found['val'])) + super(AnalogTagDataBlock, self).setValues(address, tag_found['val']) + super(AnalogTagDataBlock, self).setValues(address + 3, 0) + + return super(AnalogTagDataBlock, self).getValues(address, count=count) + + def setValues(self, address, value): + ''' Sets the requested values of the datastore + + :param address: The starting address + :param values: The new values to be set + ''' + client = MongoClient() + db = client.tag_data + tags = db.tag_vals + tag_name = tags.find_one({'register_number': address, 'register_type': self.register_type})['tag_name'] + plc.writeTag(PLC_IP_ADDRESS, tag_name, value) + + +def main(): + # ---------------------------------------------------------------------------# + # initialize your data store + # ---------------------------------------------------------------------------# + tags_in_db = getTagsFromDB() + di_block = DigitalTagDataBlock('di', tags_in_db['di']) + co_block = DigitalTagDataBlock('co', tags_in_db['co']) + hr_block = AnalogTagDataBlock('hr', tags_in_db['hr']) + ir_block = AnalogTagDataBlock('ir', tags_in_db['ir']) + store = ModbusSlaveContext(di=di_block, co=co_block, hr=hr_block, ir=ir_block) + context = ModbusServerContext(slaves=store, single=True) + + # ---------------------------------------------------------------------------# + # initialize the server information + # ---------------------------------------------------------------------------# + identity = ModbusDeviceIdentification() + identity.VendorName = 'pymodbus' + identity.ProductCode = 'PM' + identity.VendorUrl = 'http://github.com/bashwork/pymodbus/' + identity.ProductName = 'pymodbus Server' + identity.ModelName = 'pymodbus Server' + identity.MajorMinorRevision = '1.0' + + # ---------------------------------------------------------------------------# + # run the server you want + # ---------------------------------------------------------------------------# + StartTcpServer(context, identity=identity, address=("localhost", 5020)) + +if __name__ == '__main__': + main() diff --git a/test.py b/test.py new file mode 100644 index 0000000..ebb85dd --- /dev/null +++ b/test.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python +''' +Pymodbus Synchronous Client Examples +-------------------------------------------------------------------------- +The following is an example of how to use the synchronous modbus client +implementation from pymodbus. +It should be noted that the client can also be used with +the guard construct that is available in python 2.5 and up:: + with ModbusClient('127.0.0.1') as client: + result = client.read_coils(1,10) + print result +''' +# ---------------------------------------------------------------------------# +# import the various server implementations +# ---------------------------------------------------------------------------# +from pymodbus.client.sync import ModbusTcpClient as ModbusClient +# from pymodbus.client.sync import ModbusUdpClient as ModbusClient +# from pymodbus.client.sync import ModbusSerialClient as ModbusClient + +# ---------------------------------------------------------------------------# +# configure the client logging +# ---------------------------------------------------------------------------# +import logging +logging.basicConfig() +log = logging.getLogger() +log.setLevel(logging.INFO) +# ---------------------------------------------------------------------------# +# choose the client you want +# ---------------------------------------------------------------------------# +# make sure to start an implementation to hit against. For this +# you can use an existing device, the reference implementation in the tools +# directory, or start a pymodbus server. +# +# If you use the UDP or TCP clients, you can override the framer being used +# to use a custom implementation (say RTU over TCP). By default they use the +# socket framer:: +# +# client = ModbusClient('localhost', port=5020, framer=ModbusRtuFramer) +# +# It should be noted that you can supply an ipv4 or an ipv6 host address for +# both the UDP and TCP clients. +# +# There are also other options that can be set on the client that controls +# how transactions are performed. The current ones are: +# +# * retries - Specify how many retries to allow per transaction (default = 3) +# * retry_on_empty - Is an empty response a retry (default = False) +# * source_address - Specifies the TCP source address to bind to +# +# Here is an example of using these options:: +# +# client = ModbusClient('localhost', retries=3, retry_on_empty=True) +# ---------------------------------------------------------------------------# +client = ModbusClient('localhost', port=5020) +# client = ModbusClient(method='ascii', port='/dev/pts/2', timeout=1) +# client = ModbusClient(method='rtu', port='/dev/pts/2', timeout=1) +client.connect() + +# ---------------------------------------------------------------------------# +# specify slave to query +# ---------------------------------------------------------------------------# +# The slave to query is specified in an optional parameter for each +# individual request. This can be done by specifying the `unit` parameter +# which defaults to `0x00` +# ---------------------------------------------------------------------------# +print("HOLDING REGISTERS") +for i in range(0, 21): + rd = client.read_holding_registers(i * 5, 5) + print rd.registers + +print("INPUT REGISTERS") +for i in range(2, 125): + rd = client.read_input_registers(i * 5, 5) + print rd.registers + +# ---------------------------------------------------------------------------# +# close the client +# ---------------------------------------------------------------------------# +client.close()