AdvancedHMI Software
General Category => Support Questions => Topic started by: hektop on October 08, 2015, 12:22:13 PM
-
I want to log PLC data to a SQL database every time a change occurs in the PLC. I have both MicroLogix and CompactLogix PLCs, so far all the testing has been done in MicroLogix, all the PLC information data such as the IP, Tags and driver type are also stored in the database. When the window loads, I create an EthernetIPforSLCMicroCom array, a DataSubscriber2 array and a PLCAddressItem array, because I might have 1 or 25 different PLCs to log, each with 1 or 50 different tags to log. I already checked the code multiple times and everything seems like it would have to run fine. The problem is that when the data changes the event handler is not firing up. I already checked multiple post regarding dataChanged but I continue with same problem. Any help? Thanks in advanced
'MicroLogix
For Each rowMicroLogixDistinctIPs As DataRow In dtMicroLogixDistinctIPs.Rows 'each row contains an unique IP
Dim _ping As New Ping
Try
Dim _pingReply = _ping.Send(rowMicroLogixDistinctIPs.Item(0).ToString(), 1000) 'ping PLC to see if it is online
If _pingReply.Status = IPStatus.Success Then 'if it is pingable
If IsNothing(MicroDriver(indexPLCMicroDriver)) Then 'if driver has not been initialized
MicroDriver(indexPLCMicroDriver) = New EthernetIPforSLCMicroCom(Me.components) 'MicroDriver is initialized
End If
MicroDriver(indexPLCMicroDriver).IPAddress = rowMicroLogixDistinctIPs.Item(0).ToString() 'assigns IP to driver
MicroDriver(indexPLCMicroDriver).PollRateOverride = 1000 'check data every 1000 milliseconds
'SQL Query output for following dataTable
'PLC_ID IP IPDescription ControllerType TagName TagDescription Location StartTime EndTime
' 1 10.103.12.23 Press MicroLogix ST41:0 Current Running Model Cell 2 2015-09-07 17:01:00.000 2020-09-07 17:01:00.000
Dim dtAllTagsFromOneIP As DataTable = SQLQuery.SelectAllTagsFromOneIP(rowMicroLogixDistinctIPs.Item(0).ToString()) 'gets all Tags that correspond to PLC/IP
Dim totalAllTagsFromOneIP As Integer = dtAllTagsFromOneIP.Rows.Count 'assigns the number of total tags that correspond to one IP
Dim PLCAddressItem(totalAllTagsFromOneIP) As PLCAddressItem 'creates an PLCAddressItem array and assigns the total tags
Dim indexPLCAddressItem As Integer = 1
For Each rowAllTagsFromOneIP As DataRow In dtAllTagsFromOneIP.Rows 'For each tag
If IsNothing(PLCAddressItem(indexPLCAddressItem)) Then 'if PLCAddressPLC has not been initialized
PLCAddressItem(indexPLCAddressItem) = New PLCAddressItem 'PLCAddressItem is initialized
End If
PLCAddressItem(indexPLCAddressItem).LastValue = Nothing 'assigns last value
PLCAddressItem(indexPLCAddressItem).NumberOfElements = 1 'assigns number of elements
PLCAddressItem(indexPLCAddressItem).PLCAddress = rowAllTagsFromOneIP.Item(4).ToString() 'assigns PLC address
PLCAddressItem(indexPLCAddressItem).ScaleFactor = 1.0R 'assigns scale factor
PLCAddressItem(indexPLCAddressItem).ScaleOffset = 0R 'assigns scale off set
PLCAddressItem(indexPLCAddressItem).SubscriptionID = 0 'assigns subscription ID
If IsNothing(DataSubsMicro(indexPLCMicroDriver)) Then ' if dataSubcription2 has not been initialized
DataSubsMicro(indexPLCMicroDriver) = New DataSubscriber2 'DataSubsMicro is initialized
DataSubsMicro(indexPLCMicroDriver).CommComponent = MicroDriver(indexPLCMicroDriver) 'assigns driver to datasubscriber
End If
DataSubsMicro(indexPLCMicroDriver).PLCAddressValueItems.Add(PLCAddressItem(indexPLCAddressItem)) 'adds to DataSubcriber2 the recently created PLCAddressItem
DataSubsMicro(indexPLCMicroDriver).PollRate = 1000 'assigns to DataSubscriber2 the poll rate
DataSubsMicro(indexPLCMicroDriver).SynchronizingObject = Me 'assigns to DataSubscriber2 the synchronizing object
DataSubsMicro(indexPLCMicroDriver).Value = Nothing 'assigns to DataSubscriber2 the value
indexPLCAddressItem += 1 'increases the index for the PLCAddressItems
Next
AddHandler DataSubsMicro(indexPLCMicroDriver).DataChanged, AddressOf DataChanged 'adds a event handler to data changed
End If
Catch ex As Exception
MsgBox("AdvancedHMI error: " + ex.Message)
Finally
indexPLCMicroDriver += 1 'increases the index used for the PLC drivers and DataSubscribers2
End Try
Next
MsgBox("done loading")
End Sub
Private Sub DataChanged(sender As Object, e As Drivers.Common.PlcComEventArgs)
MsgBox("e.values: " + e.Values(0).ToString() + "; e.PLCAddress: " + e.PlcAddress)
End Sub
-
Forgot to include the following, I am using the AHMI399a solution and also I am using MS VS 2015 express
-
The DataSubscriber was designed to make subscribing easy without the need to write code using the Visual Designer. Since you are doing everything in code, it will be better to directly subscribe to the driver and not use a DataSubscriber. Later today I will post an example of how to do this.
-
Here is an example of subscribing directly via code:
Private SubscriptionID As Integer
Private Sub MainForm_Load(sender As Object, e As EventArgs) Handles MyBase.Load
EthernetIPforCLXCom1.Subscribe("MyTag", 1, 500, AddressOf DataReturned)
End Sub
Private LastValue As String
Private Sub DataReturned(ByVal sender As Object, ByVal e As MfgControl.AdvancedHMI.Drivers.Common.PlcComEventArgs)
If e.PlcAddress = "MyTag" Then
If e.Values(0) <> LastValue Then
'* Do something here for the value changed
LastValue = e.Values(0)
End If
End If
End Sub
Private Sub MainFormX_FormClosing(sender As Object, e As Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
'*Release the subscription so the driver stops reading from the PLC
EthernetIPforCLXCom1.UnSubscribe(SubscriptionID)
End Sub
-
Wow the code is much simpler. I apparently I was making things more complicated than what it had to be. Thank you very much for your help. Apparently AHMI has it all. Good job Archie.
-
Archie, one more question. Is there a way to know from which IP the data is coming using subscribers. Lets take the following example.
EthernetIPforCLXCom1.Subscribe("MyTag", 1, 500, AddressOf DataReturned)
EthernetIPforCLXCom2.Subscribe("MyTag", 1, 500, AddressOf DataReturned)
Private LastValue As String
Private Sub DataReturned(ByVal sender As Object, ByVal e As Drivers.Common.PlcComEventArgs)
If e.PlcAddress = "ST41:11" And e.IP = "1.1.1.1" Then
If e.Values(0) <> LastValue Then
'Write to SQL
LastValue = e.Values(0)
End If
ElseIf e.PlcAddress = "ST41:11" And e.IP = "2.2.2.2" Then
If e.Values(0) <> LastValue Then
'Write to SQL
LastValue = e.Values(0)
End If
End If
End Sub
-
I would use 2 separate DataReturned subs
EthernetIPforCLXCom1.Subscribe("MyTag", 1, 500, AddressOf DataReturnedA)
EthernetIPforCLXCom2.Subscribe("MyTag", 1, 500, AddressOf DataReturnedB)
Private Sub DataReturnedA(ByVal sender As Object, ByVal e As Drivers.Common.PlcComEventArgs)
End Sub
Private Sub DataReturnedB(ByVal sender As Object, ByVal e As Drivers.Common.PlcComEventArgs)
End Sub
-
I forgot to reply back but I found a way to do it without creating multiple DataReturn subs
Private Sub CLXDataReturned(ByVal sender As Object, ByVal e As Drivers.Common.PlcComEventArgs)
Dim PlcIp, PlcTag, PlcValue As String
Try
Dim DriverComm As AdvancedHMIDrivers.EthernetIPforCLXCom = CType(sender, AdvancedHMIDrivers.EthernetIPforCLXCom) This is the important part
PlcIp = DriverComm.IPAddress This is how I get the IP value
PlcTag = e.PlcAddress
PlcValue = e.Values(0).ToString()
comparePLCDataWithSQL(PlcIP, PlcTag, PlcValue)
Catch ex As Exception
SQLQuery.InsertInto4FieldsQuery("tblErrorLog", "IP", sender.IPAddress, "LogTime", Now.ToString("yyyy-MM-dd HH:mm:ss.fff"), "Error", ex.Message, "Tag", e.PlcAddress)
End Try
End Sub