Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package com.milesmarine.reeflightcontroller
- import android.content.Intent
- import android.os.Bundle
- import android.util.Log
- import android.view.View
- import android.widget.LinearLayout
- import android.widget.TextView
- import androidx.appcompat.app.AppCompatActivity
- import androidx.recyclerview.widget.LinearLayoutManager
- import androidx.recyclerview.widget.RecyclerView
- import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
- import kotlinx.coroutines.CoroutineScope
- import kotlinx.coroutines.Dispatchers
- import kotlinx.coroutines.delay
- import kotlinx.coroutines.launch
- import org.json.JSONObject
- import java.net.DatagramPacket
- import java.net.DatagramSocket
- import java.net.HttpURLConnection
- import java.net.InetAddress
- import java.net.URL
- class SecondActivity : AppCompatActivity() {
- private lateinit var recyclerView: RecyclerView
- private lateinit var adapter: DeviceAdapter
- private val deviceList = mutableListOf<OpenBekenDevice>()
- // UI Elements for the loading screen
- private lateinit var loadingLayout: LinearLayout
- private lateinit var loaderText: TextView
- // Swipe-to-refresh layout
- private lateinit var swipeRefreshLayout: SwipeRefreshLayout
- // SSDP Multicast Address and Port
- private val SSDP_ADDRESS = "239.255.255.250"
- private val SSDP_PORT = 1900
- private val SSDP_MESSAGE = """
- M-SEARCH * HTTP/1.1
- HOST: $SSDP_ADDRESS:$SSDP_PORT
- MAN: "ssdp:discover"
- MX: 3
- ST: ssdp:all
- """.trimIndent()
- override fun onCreate(savedInstanceState: Bundle?) {
- super.onCreate(savedInstanceState)
- setContentView(R.layout.activity_second)
- // Initialize RecyclerView
- recyclerView = findViewById(R.id.recyclerViewDevices)
- recyclerView.layoutManager = LinearLayoutManager(this)
- val onDeviceClick: (OpenBekenDevice) -> Unit = { device ->
- // Save the selected device's IP to SharedPreferences
- val sharedPreferences = getSharedPreferences("DevicePrefs", MODE_PRIVATE)
- val editor = sharedPreferences.edit()
- editor.putString("selectedDeviceIP", device.ip)
- editor.apply()
- // Send selected device IP back to MainActivity
- val resultIntent = Intent()
- resultIntent.putExtra("selectedDeviceIP", device.ip)
- setResult(RESULT_OK, resultIntent)
- finish() // Close SecondActivity after selection
- }
- // Set up the adapter with the onDeviceClick function
- adapter = DeviceAdapter(deviceList, onDeviceClick)
- recyclerView.adapter = adapter
- // Initialize loading screen elements
- loadingLayout = findViewById(R.id.loadingLayout)
- loaderText = findViewById(R.id.loaderText)
- // Initialize SwipeRefreshLayout
- swipeRefreshLayout = findViewById(R.id.swipeRefreshLayout)
- // Set up the SwipeRefreshLayout listener
- swipeRefreshLayout.setOnRefreshListener {
- // Reset device list and start the discovery process
- deviceList.clear()
- adapter.notifyDataSetChanged() // Notify adapter to refresh RecyclerView
- Log.d("SwipeRefresh", "Swipe-to-refresh triggered")
- // Start SSDP discovery
- discoverDevicesUsingSSDP()
- }
- // Start SSDP discovery on initial launch
- discoverDevicesUsingSSDP()
- }
- private fun discoverDevicesUsingSSDP() {
- Log.d("SSDP", "Starting SSDP discovery")
- // Show the loading screen
- showLoadingScreen()
- // Use a Coroutine to perform the discovery in the background
- CoroutineScope(Dispatchers.IO).launch {
- try {
- // Open a socket to send and receive SSDP messages
- DatagramSocket().use { socket ->
- // Configure the socket to broadcast and join multicast group
- val multicastAddress = InetAddress.getByName(SSDP_ADDRESS)
- val packet = DatagramPacket(
- SSDP_MESSAGE.toByteArray(),
- SSDP_MESSAGE.length,
- multicastAddress,
- SSDP_PORT
- )
- // Send the SSDP discovery request
- socket.send(packet)
- // Receive responses
- val buffer = ByteArray(1024)
- while (true) {
- val responsePacket = DatagramPacket(buffer, buffer.size)
- socket.receive(responsePacket)
- // Parse the response to extract the device details
- val response = String(responsePacket.data, 0, responsePacket.length)
- handleSSDPResponse(response, responsePacket.address.hostAddress)
- }
- }
- } catch (e: Exception) {
- e.printStackTrace()
- } finally {
- // Hide loading screen after discovery is done
- hideLoadingScreen()
- // Update the RecyclerView with the devices found so far
- runOnUiThread {
- // Notify adapter about data change after the scan finishes
- adapter.notifyDataSetChanged()
- Log.d("SSDP", "Discovery completed. Devices: ${deviceList.size}")
- // Stop the swipe refresh animation when done
- if (swipeRefreshLayout.isRefreshing) {
- swipeRefreshLayout.isRefreshing = false
- }
- }
- }
- }
- // Set a timeout to hide the loading screen after 5 seconds if still refreshing
- CoroutineScope(Dispatchers.Main).launch {
- delay(5000)
- // Hide loading screen even if discovery did not complete within 10 seconds
- hideLoadingScreen()
- // Stop refresh animation if still active
- if (swipeRefreshLayout.isRefreshing) {
- swipeRefreshLayout.isRefreshing = false
- }
- runOnUiThread {
- // Make sure the UI is updated
- adapter.notifyDataSetChanged()
- Log.d("SSDP", "Discovery timed out after 10 seconds")
- }
- }
- }
- private fun handleSSDPResponse(response: String, ipAddress: String) {
- Log.d("SSDP", "Received response: $response from $ipAddress")
- // Check if the response matches an OpenBeken device
- if (response.contains("OpenBk", ignoreCase = true)) {
- // Extract the LOCATION header from the response
- val locationRegex = Regex("(?i)LOCATION:\\s*(http://[\\d.]+:\\d+/ssdp\\.xml)")
- val locationMatch = locationRegex.find(response)
- val location = locationMatch?.groups?.get(1)?.value ?: ""
- // Send HTTP request to get the MAC address
- CoroutineScope(Dispatchers.IO).launch {
- val macAddress = getMacAddress(ipAddress)
- // Create an OpenBekenDevice object with the extracted details
- val device = OpenBekenDevice(ipAddress, macAddress)
- runOnUiThread {
- // Add the device to the list and update RecyclerView
- if (deviceList.none { it.ip == ipAddress }) { // Avoid duplicates
- deviceList.add(device)
- adapter.notifyDataSetChanged() // Notify adapter after updating the list
- }
- }
- }
- }
- }
- // Function to send HTTP request and get MAC address from the device's Status command
- private fun getMacAddress(ipAddress: String): String {
- return try {
- val url = URL("http://$ipAddress/cm?cmnd=Status")
- val connection = url.openConnection() as HttpURLConnection
- connection.requestMethod = "GET"
- connection.connect()
- // Read the response
- val response = connection.inputStream.bufferedReader().readText()
- // Log the full response for debugging
- Log.d("OpenBekenResponse", "Response from $ipAddress: $response")
- // Parse the JSON response
- val jsonResponse = JSONObject(response)
- // Extract MAC address from the StatusNET section
- if (jsonResponse.has("StatusNET")) {
- val statusNet = jsonResponse.getJSONObject("StatusNET")
- val macAddress = statusNet.getString("Mac")
- Log.d("OpenBekenResponse", "MAC Address: $macAddress")
- macAddress
- } else {
- Log.d("OpenBekenResponse", "StatusNET not found in response")
- "MAC address not found"
- }
- } catch (e: Exception) {
- e.printStackTrace()
- "Unknown MAC Address"
- }
- }
- // Show the loading screen
- private fun showLoadingScreen() {
- Log.d("UI", "Showing loading screen")
- runOnUiThread {
- loadingLayout.visibility = View.VISIBLE
- recyclerView.visibility = View.GONE // Hide the RecyclerView during loading
- }
- }
- // Hide the loading screen
- private fun hideLoadingScreen() {
- Log.d("UI", "Hiding loading screen")
- runOnUiThread {
- loadingLayout.visibility = View.GONE
- recyclerView.visibility = View.VISIBLE // Show the RecyclerView after loading
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement