diff --git a/app/src/main/aidl/com/geeksville/mesh/IMeshService.aidl b/app/src/main/aidl/com/geeksville/mesh/IMeshService.aidl
index 4914c024..d303b025 100644
--- a/app/src/main/aidl/com/geeksville/mesh/IMeshService.aidl
+++ b/app/src/main/aidl/com/geeksville/mesh/IMeshService.aidl
@@ -95,6 +95,12 @@ interface IMeshService {
/// It sets a ChannelSet protobuf
void setChannels(in byte []payload);
+ /// Send Shutdown admin packet to nodeNum
+ void requestShutdown(in String nodeId);
+
+ /// Send Reboot admin packet to nodeNum
+ void requestReboot(in String nodeId);
+
/**
Is the packet radio currently connected to the phone? Returns a ConnectionState string.
*/
diff --git a/app/src/main/java/com/geeksville/mesh/model/UIState.kt b/app/src/main/java/com/geeksville/mesh/model/UIState.kt
index 7d46a6f8..ec3641f2 100644
--- a/app/src/main/java/com/geeksville/mesh/model/UIState.kt
+++ b/app/src/main/java/com/geeksville/mesh/model/UIState.kt
@@ -279,6 +279,14 @@ class UIViewModel @Inject constructor(
}
}
+ fun requestShutdown() {
+ meshService?.requestShutdown(DataPacket.ID_LOCAL)
+ }
+
+ fun requestReboot() {
+ meshService?.requestReboot(DataPacket.ID_LOCAL)
+ }
+
/**
* Write the persisted packet data out to a CSV file in the specified location.
*/
diff --git a/app/src/main/java/com/geeksville/mesh/service/MeshService.kt b/app/src/main/java/com/geeksville/mesh/service/MeshService.kt
index ac7c7b75..5bf23041 100644
--- a/app/src/main/java/com/geeksville/mesh/service/MeshService.kt
+++ b/app/src/main/java/com/geeksville/mesh/service/MeshService.kt
@@ -1406,6 +1406,18 @@ class MeshService : Service(), Logging {
})
}
+ private fun requestShutdown(nodeId: String) {
+ sendToRadio(newMeshPacketTo(toNodeNum(nodeId)).buildAdminPacket {
+ shutdownSeconds = 5
+ })
+ }
+
+ private fun requestReboot(nodeId: String) {
+ sendToRadio(newMeshPacketTo(toNodeNum(nodeId)).buildAdminPacket {
+ rebootSeconds = 5
+ })
+ }
+
/**
* Start the modern (REV2) API configuration flow
*/
@@ -1763,6 +1775,14 @@ class MeshService : Service(), Logging {
override fun stopProvideLocation() = toRemoteExceptions {
stopLocationRequests()
}
+
+ override fun requestShutdown(nodeId: String) = toRemoteExceptions {
+ this@MeshService.requestShutdown(nodeId)
+ }
+
+ override fun requestReboot(nodeId: String) = toRemoteExceptions {
+ this@MeshService.requestReboot(nodeId)
+ }
}
}
diff --git a/app/src/main/java/com/geeksville/mesh/ui/AdvancedSettingsFragment.kt b/app/src/main/java/com/geeksville/mesh/ui/AdvancedSettingsFragment.kt
index 05c32525..5f86ef62 100644
--- a/app/src/main/java/com/geeksville/mesh/ui/AdvancedSettingsFragment.kt
+++ b/app/src/main/java/com/geeksville/mesh/ui/AdvancedSettingsFragment.kt
@@ -14,6 +14,7 @@ import com.geeksville.mesh.model.ChannelOption
import com.geeksville.mesh.model.UIViewModel
import com.geeksville.mesh.service.MeshService
import com.geeksville.util.exceptionToSnackbar
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.snackbar.Snackbar
import dagger.hilt.android.AndroidEntryPoint
@@ -52,6 +53,8 @@ class AdvancedSettingsFragment : ScreenFragment("Advanced Settings"), Logging {
binding.lsSleepView.isEnabled = connected && model.isPowerSaving ?: false
binding.positionBroadcastSwitch.isEnabled = connected
binding.lsSleepSwitch.isEnabled = connected
+ binding.shutdownButton.isEnabled = connected
+ binding.rebootButton.isEnabled = connected
}
binding.positionBroadcastPeriodEditText.on(EditorInfo.IME_ACTION_DONE) {
@@ -106,5 +109,27 @@ class AdvancedSettingsFragment : ScreenFragment("Advanced Settings"), Logging {
debug("User changed isPowerSaving to $isChecked")
}
}
+
+ binding.shutdownButton.setOnClickListener {
+ MaterialAlertDialogBuilder(requireContext())
+ .setMessage("${getString(R.string.update_firmware)}?")
+ .setNeutralButton(R.string.cancel) { _, _ ->
+ }
+ .setPositiveButton(getString(R.string.okay)) { _, _ ->
+ model.requestShutdown()
+ }
+ .show()
+ }
+
+ binding.rebootButton.setOnClickListener {
+ MaterialAlertDialogBuilder(requireContext())
+ .setMessage("${getString(R.string.update_firmware)}?")
+ .setNeutralButton(R.string.cancel) { _, _ ->
+ }
+ .setPositiveButton(getString(R.string.okay)) { _, _ ->
+ model.requestReboot()
+ }
+ .show()
+ }
}
}
\ No newline at end of file
diff --git a/app/src/main/res/layout/advanced_settings.xml b/app/src/main/res/layout/advanced_settings.xml
index 79f1dfe8..5d22f6a5 100644
--- a/app/src/main/res/layout/advanced_settings.xml
+++ b/app/src/main/res/layout/advanced_settings.xml
@@ -65,4 +65,27 @@
app:layout_constraintBottom_toBottomOf="@id/lsSleepView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/lsSleepView" />
+
+
+
+
\ No newline at end of file