The Idea!
Develop a system that enables a Google Pixel smartphone (or any Android One device) to send an SOS message to a Nexus device via a satellite network. This project serves as a clear example of multi-protocol bridging, seamlessly connecting different types of communication signals.
The Input: The user sends a message from their Pixel smartphone.
The Bridge: The message travels via Bluetooth (using an HC-05 module) to an Arduino.
*Hardware Architecture: The Nexus is capable of direct multi-protocol interfacing. However, I implemented an Arduino bridge as a deliberate design choice. This creates a isolates external user data from the Nexus's internal proprietary code and industrial secrets.
The Uplink: The Arduino then converts that data and sends it to the Nexus device using LoRa (Long Range) radio signals.
The Network: The message is sent to the Fossa Systems satellite constellation for global coverage using LoRa.
The Workflow:
Smartphone App: A custom Android app sends an SOS command via Bluetooth.
Arduino Bridge: An Arduino UNO R4 Minima acts as interface, receiving the signal and forwarding a precise 32-byte payload via I2C.
Satellite Link: The Fossa Nexus receives the data and uses LoRa modulation to transmit the SOS message from the ground directly to a satellite orbit.
This demo illustrates how a simple mobile application can trigger long-range, orbital communication for emergency or remote monitoring scenarios.
Note: This is an independent and technical demonstration. For commercial inquiries or official hardware specifications, please contact Fossa Systems directly.
Android Device: A smartphone (e.g., Google Pixel) running Android 12 or later, used to handle the user interface and initiate message transmission.
HC-05 Bluetooth Module: Used to establish a Bluetooth serial connection between the smartphone and the local controller.
Arduino: A development board that receives incoming data and acts as the local controller.
Nexus (by Fossa Systems): The core industrial-grade communication terminal that manages multi-protocol bridging, performs high-level data processing, and sends the SOS message to the satellite.
Fossa Systems Satellite Constellation Access: Receives the LoRa uplink from the Nexus to enable global message delivery.
Interconnect Cables: High-quality jumper wires and connectors that ensure stable data connections between the Arduino, HC-05, and Nexus.
Start with the entry-level Android SOS application, developed using Android Studio.
Download it here on your PC https://developer.android.com
Open it and install it in standard mode
Prepare the device in developer mode:
To allow Android Studio to detect your Pixel device and install the SOS application, you need to unlock developer options on the phone:
On your Pixel, go to Settings > About phone.
Tap Build number 7 times. A message will appear: “You are now a developer!”
Go back and navigate to System > Developer options.
Enable USB debugging.
Go back to Android Studio – XML part:
Create the app’s “ID card” so the Android operating system knows what app we are developing and what permissions it will require.
Copy and paste the code into AndroidManifest.xml
This is usually the basic setup for an Android application designed to communicate with hardware, such as an Arduino in this case.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.ArduinoSOS">
<activity
android:name=".MainActivity"
android:exported="true"
android:label="@string/app_name"
android:theme="@style/Theme.ArduinoSOS">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
</manifest>
Open MainActivity.kt and copy and paste the following code:
package com.example.arduinosos
import android.annotation.SuppressLint
import android.bluetooth.BluetoothAdapter
import android.bluetooth.BluetoothManager
import android.bluetooth.BluetoothSocket
import android.content.Context
import android.os.Bundle
import android.widget.Toast
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.size
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import com.example.arduinosos.ui.theme.ArduinoSOSTheme
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.OutputStream
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.util.UUID
class MainActivity : ComponentActivity() {
private var btSocket: BluetoothSocket? = null
private var outputStream: OutputStream? = null
private var packetCounter = 0
private val MY_UUID: UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB")
@SuppressLint("MissingPermission")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
ArduinoSOSTheme {
val context = LocalContext.current
// Creiamo un "lavoratore" per le operazioni in background
val coroutineScope = rememberCoroutineScope()
Column(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
// --- PULSANTE 1: CONNETTI ---
Button(
onClick = {
val btManager = context.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
val btAdapter = btManager.adapter
try {
val hc05 = btAdapter?.bondedDevices?.find { it.name == "HC-05" }
if (hc05 != null) {
Toast.makeText(context, "Tentativo di connessione...", Toast.LENGTH_SHORT).show()
// Spostiamo la connessione in BACKGROUND (Dispatchers.IO)
coroutineScope.launch(Dispatchers.IO) {
try {
btSocket = hc05.createRfcommSocketToServiceRecord(MY_UUID)
btSocket?.connect()
outputStream = btSocket?.outputStream
// Torniamo sul Main Thread solo per mostrare il Toast di successo
withContext(Dispatchers.Main) {
Toast.makeText(context, "Connesso a HC-05!", Toast.LENGTH_SHORT).show()
}
} catch (e: Exception) {
withContext(Dispatchers.Main) {
Toast.makeText(context, "Errore connessione: riprova", Toast.LENGTH_SHORT).show()
}
}
}
} else {
Toast.makeText(context, "HC-05 non trovato nei dispositivi associati!", Toast.LENGTH_LONG).show()
}
} catch (e: SecurityException) {
// Se arrivi qui, il permesso Bluetooth non è stato dato correttamente
Toast.makeText(context, "CRITICO: Manca l'autorizzazione Bluetooth nelle impostazioni!", Toast.LENGTH_LONG).show()
}
},
colors = ButtonDefaults.buttonColors(containerColor = Color.DarkGray)
) {
Text("1. Connetti HC-05", color = Color.White)
}
Spacer(modifier = Modifier.height(32.dp))
// --- PULSANTE 2: INVIA SOS ---
Button(
onClick = {
if (outputStream == null) {
Toast.makeText(context, "Devi prima connetterti!", Toast.LENGTH_SHORT).show()
return@Button
}
packetCounter++
val pacchettoDati = createSosPacket(packetCounter, true)
// Anche l'invio dati è meglio farlo in background
coroutineScope.launch(Dispatchers.IO) {
try {
outputStream?.write(pacchettoDati)
outputStream?.flush()
withContext(Dispatchers.Main) {
Toast.makeText(context, "SOS INVIATO! ($packetCounter)", Toast.LENGTH_SHORT).show()
}
} catch (e: Exception) {
withContext(Dispatchers.Main) {
Toast.makeText(context, "Errore durante l'invio", Toast.LENGTH_SHORT).show()
}
}
}
},
colors = ButtonDefaults.buttonColors(containerColor = Color.Red),
modifier = Modifier.size(200.dp)
) {
Text("2. INVIA SOS", color = Color.White, fontWeight = FontWeight.Bold)
}
}
}
}
}
private fun createSosPacket(counter: Int, isSos: Boolean): ByteArray {
val buffer = ByteBuffer.allocate(32)
buffer.order(ByteOrder.LITTLE_ENDIAN)
buffer.putInt(counter) // 0-3
val sosValue = if (isSos) 1.0f else 0.0f
buffer.putFloat(sosValue) // 4-7
for (i in 8..31) { buffer.put(i.toByte()) } // 8-31
return buffer.array()
}
}
Now connect your Android device (I’m using a Pixel 7) via USB. In Android Studio, select your device from the dropdown at the top, then press the Play button to run the app.
You’ll know it’s working when you see “Gradle Build Running” at the bottom of the screen. The first build may take up to 5 minutes.
Make sure Developer Mode is enabled and that the Android SOS application has been granted all necessary permissions, including Bluetooth access.
The HC-05 Bluetooth implementation and the SOS button should now be working.
Using an Arduino R4 Minima (an Italian innovation, formerly a flagship 🥰).
Arduino Code:
Arduino Ide
#include <Arduino.h>
#include <Wire.h>
// Configurazione I2C del Nexus
const uint8_t I2C_ADDRESS = 0x55;
// Struttura per leggere i 32 byte in arrivo dall'HC-05
struct __attribute__((__packed__)) MyDataPacket {
uint32_t counter;
float sosStatus;
uint8_t filler[24];
};
MyDataPacket rxPacket;
void setup() {
Serial.begin(9600); // Seriale per il Monitor del PC
Serial1.begin(9600); // Seriale Hardware per l'HC-05 (Pin 0 e 1)
// Inizializza I2C come MASTER
Wire.begin();
Serial.println(F("Arduino R4 - Bridge SOS inizializzato!"));
Serial.println(F("In attesa che premi il pulsante sull'App..."));
}
void loop() {
// ===== ASPETTA IL COMANDO DAL BLUETOOTH =====
// Entra qui dentro SOLO quando premi il pulsante sull'app
if (Serial1.available() >= sizeof(rxPacket)) {
// 1. Legge i dati dal Pixel
byte* p = (byte*)&rxPacket;
for (int i = 0; i < sizeof(rxPacket); i++) {
p[i] = Serial1.read();
}
uint32_t currentCounter = rxPacket.counter;
float currentSos = rxPacket.sosStatus;
Serial.print(F("\n[+] Clic su App! Counter: "));
Serial.print(currentCounter);
Serial.print(F(" | SOS: "));
Serial.println(currentSos == 1.0f ? "ATTIVO!" : "OK");
// Svuota il buffer Seriale per evitare pacchetti doppi o sporchi
while(Serial1.available() > 0) Serial1.read();
// ===== 2. INOLTRA IMMEDIATAMENTE AL NEXUS VIA I2C =====
uint8_t msg[32] = {0};
// byte 0-3 : counter
memcpy(&msg[0], ¤tCounter, sizeof(currentCounter));
// byte 4-7 : SOS status
memcpy(&msg[4], ¤tSos, sizeof(float));
// byte 8-31 : filler (8, 9, 10... 31)
for (int i = 8; i < 32; i++) {
msg[i] = i;
}
// Invia il pacchetto
Wire.beginTransmission(I2C_ADDRESS);
Wire.write(msg, 32);
uint8_t error = Wire.endTransmission();
// Feedback sul monitor seriale
if (error == 0) {
Serial.println(F(" -> I2C: Pacchetto inoltrato con successo al Nexus."));
} else {
Serial.print(F(" -> I2C: ERRORE di trasmissione (Codice: "));
Serial.print(error);
Serial.println(F(")"));
}
}
}