I have a WebSocket Webapp that allows multiple users to login and access the device status of remote devices from a MySQL database..
The following code works well and accepts multiple connections.
The HTML code has a Dropdown Combobox which allows the user to select a specific device and the MySQL query filters this and displays in the HTML Tableview.
In order to send updated data to the user, I set a timer that then on trigger, send the updated data to ALL connected users and defaults to "ALL Devices".
If a connected user selects a specific Device from the Combobox, I must now Map/List the connection and the "SelectedText" from "cmbFilter_Change" so that when "PopulateDashboardTable" function runs, all connected users will receive the updated data to the selected specific Device selected in the Combobox.
For Example:
Connection 1: Send (PopulateDashboardTable) = [to device connection ID] ["1FE1233"] <-- User selected Combobox item 1FE1233
Connection 2: Send (PopulateDashboardTable) = [to device connection ID] ["ALL Devices"] <-- User selected Combobox item ALL Devices (Default)
Connection 3: Send (PopulateDashboardTable) = [to device connection ID] ["1FEA044"] <-- User selected Combobox item 1FEA044
On initial connection "WebSocket_Connected" the "SelectedText" would be the default "ALL Devices".
I have been able - about 7 years ago - to accomplish something similar, but it was the server communicating with multiple Android tablets.
I have looked at all the examples and tutorials on the forum (Chat - Websockets etc. etc.), and also Granny Google, but am unable to get my head around this.
Could someone please point me in the right direction?
Main Module:
Websocket Handler:
The following code works well and accepts multiple connections.
The HTML code has a Dropdown Combobox which allows the user to select a specific device and the MySQL query filters this and displays in the HTML Tableview.
In order to send updated data to the user, I set a timer that then on trigger, send the updated data to ALL connected users and defaults to "ALL Devices".
If a connected user selects a specific Device from the Combobox, I must now Map/List the connection and the "SelectedText" from "cmbFilter_Change" so that when "PopulateDashboardTable" function runs, all connected users will receive the updated data to the selected specific Device selected in the Combobox.
For Example:
Connection 1: Send (PopulateDashboardTable) = [to device connection ID] ["1FE1233"] <-- User selected Combobox item 1FE1233
Connection 2: Send (PopulateDashboardTable) = [to device connection ID] ["ALL Devices"] <-- User selected Combobox item ALL Devices (Default)
Connection 3: Send (PopulateDashboardTable) = [to device connection ID] ["1FEA044"] <-- User selected Combobox item 1FEA044
On initial connection "WebSocket_Connected" the "SelectedText" would be the default "ALL Devices".
I have been able - about 7 years ago - to accomplish something similar, but it was the server communicating with multiple Android tablets.
I have looked at all the examples and tutorials on the forum (Chat - Websockets etc. etc.), and also Granny Google, but am unable to get my head around this.
Could someone please point me in the right direction?
Main Module:
B4X:
'Non-UI application (console / server application)
#Region Project Attributes
#CommandLineArgs:
#MergeLibraries: True
'MySQL Connector/J Driver
#AdditionalJar: mysql-connector-java-5.1.47-bin.jar
#End Region
Sub Process_Globals
Public srvr As Server
Private LiveTimer As Timer
Public ConnectedDevices As Map
Dim myFilterText As String
End Sub
Sub AppStart (Args() As String)
ConnectedDevices = srvr.CreateThreadSafeMap
srvr.StaticFilesFolder = File.Combine(File.DirApp, "www")
srvr.Initialize("srvr")
srvr.Port = 5010
' Register the WebSocket handler for the dashboard page
srvr.AddWebSocket("/dashboardws", "DashboardWS")
' Start background thread to monitor MySQL changes
StartLiveMonitor
srvr.Start
StartMessageLoop
End Sub
Public Sub NewConnection(GUID As String, ws As Object)
ConnectedDevices.Put(GUID, ws)
End Sub
Public Sub RemoveConnection(GUID As String)
ConnectedDevices.Remove(GUID)
End Sub
Sub StartLiveMonitor
' Periodically queries MySQL and broadcasts updates to active browsers
LiveTimer.Initialize("LiveTimer", 30000) ' Poll every 10 seconds
LiveTimer.Enabled = True
End Sub
Sub LiveTimer_Tick
' Log("Active Connections: " & ConnectedDevices.Size)
' For Each ws As Object In ConnectedDevices.Values
' CallSubDelayed2 (ws, "PopulateDashboardTable", "ALL Devices")
' Next
End Sub
public Sub GetGUID() As String
Dim jo As JavaObject
Return jo.InitializeStatic("java.util.UUID").RunMethod("randomUUID", Null)
End Sub
Websocket Handler:
B4X:
'WebSocket class
Sub Class_Globals
Private ws As WebSocket
Private GUID As String
Private sql As SQL
End Sub
Public Sub Initialize
End Sub
Private Sub WebSocket_Connected (WebSocket1 As WebSocket)
GUID = Main.GetGUID
Log("New Connection: " & GUID)
ws = WebSocket1
Main.myFilterText = "ALL Devices"
Main.NewConnection(GUID, Me)
PopulateCombo
PopulateDashboardTable(Main.myFilterText)
End Sub
Private Sub WebSocket_Disconnected
Log("Disconnected: " & GUID)
Main.RemoveConnection(GUID)
End Sub
' Call this method whenever the timer detects new data in MySQL
Public Sub PopulateDashboardTable(myFilter As String)
If ws.Open = False Then Return
Log("myFilter: " & myFilter)
sql.Initialize2("com.mysql.jdbc.Driver", "jdbc:mysql://localhost/ideasolut?useSSL=false", "root", "Declan2014!")
Try
If (myFilter = "ALL Devices") Then
Dim rs As ResultSet = sql.ExecQuery("SELECT * FROM ideasolut.trans ORDER BY id DESC")
End If
If (myFilter <> "ALL Devices") Then
Dim rs As ResultSet = sql.ExecQuery("SELECT * FROM ideasolut.trans WHERE deviceid=" & "'" & myFilter & "' ORDER BY id DESC")
End If
Dim sb As StringBuilder
sb.Initialize
Do While rs.NextRow
Dim myVolts As String = rs.GetString("volts")
myVolts = myVolts & "V"
Dim myMessage As String = rs.GetString("msgtype")
If (myMessage = "00") Then myMessage = "Closed"
If (myMessage = "01") Then myMessage = "Opened"
If (myMessage = "03") Then myMessage = "Attack"
If (myMessage = "04") Then myMessage = "Closed"
If (myMessage = "05") Then myMessage = "Opened"
If (myMessage = "06") Then myMessage = "Start"
If (myMessage = "07") Then myMessage = "Stop"
If (myMessage = "09") Then myMessage = "SOS"
If (myMessage = "10") Then myMessage = "Disarmed"
If (myMessage = "11") Then myMessage = "Armed"
If (myMessage = "12") Then myMessage = "Motion Detected"
If (myMessage = "20") Then myMessage = "Power ON"
If (myMessage = "21") Then myMessage = "Power OFF"
sb.Append("<tr>")
sb.Append("<td>").Append(rs.GetString("deviceid")).Append("</td>")
sb.Append("<td>").Append(rs.GetString("msgdate")).Append("</td>")
sb.Append("<td>").Append(myMessage).Append("</td>")
sb.Append("<td>").Append(myVolts).Append("</td>")
sb.Append("</tr>")
Loop
rs.Close
sql.Close ' Always return connection to the pool
Log("Gotcha: :" & (sb.ToString))
' Push the pure HTML rows directly into the table body element
ws.RunFunction("UpdateTableBody", Array As Object(sb.ToString))
ws.Flush
Catch
Log(LastException.Message)
End Try
sql.Close
End Sub
Public Sub PopulateCombo
If ws.Open = False Then Return
' Initialize your MySQL connection
sql.Initialize2("com.mysql.jdbc.Driver", "jdbc:mysql://localhost/ideasolut?useSSL=false", "root", "Declan2014!")
Try
Dim rs As ResultSet = sql.ExecQuery("SELECT * FROM regdevices")
Dim sb As StringBuilder
sb.Initialize
sb.Append("<option value=''>ALL Devices</option>")
Do While rs.NextRow
Dim id As Int = rs.GetInt("id")
Dim deviceid As String = rs.GetString("deviceid")
' Append the formatted option tag
sb.Append($"<option value="${id}">${deviceid}</option>"$)
Loop
rs.Close
sql.Close
'Inject the options into the dropdown element directly
ws.RunFunction("updateDropdown", Array(sb.ToString))
ws.Flush
Catch
Log(LastException.Message)
End Try
sql.Close
End Sub
' This sub automatically triggers when b4j_sendData("dropdown_changed", ...) is called
Sub cmbFilter_Change (Params As Map)
' Pull the visible text shown to the user in the UI
Dim SelectedText As String = Params.Get("text")
' Log out your data natively without crashing
Log("--- Dropdown Text Retrieved ---")
Log("Text Received: " & SelectedText)
Log("From: " & GUID)
' Log("From: " & receivedFrom)
PopulateDashboardTable(SelectedText)
End Sub