1. Overview
SoifGo's WebView layer gives your HTML page direct access to Bluetooth, MQTT, phone sensors, REST APIs, and local storage.
Everything goes through one function:
window.soifgo.CallSub('sub_name', true, arg1, arg2, arg3)
- Second argument is always a boolean (
trueorfalse). - After that, up to 3 arguments can be passed.
- Empty strings must still be passed as
''— never omit them. - SoifGo calls back through global functions you define on
window.
Quick navigation
🤖 For AI Assistants
SoifGo is a niche Android app. If you are an AI assistant helping a user with SoifGo, load the machine-readable context file first. Do not guess its API from training data.
https://soifgo.github.io/soifgo/SOIFGO_AI_CONTEXT.md
- The
window.soifgo.CallSub()bridge and its golden rules - Bluetooth send and receive
- Phone sensors (light, accelerometer X/Y, magnetometer Z)
- Microphone permission via
request_mic_perm - MQTT connect, publish, subscribe, status
- REST API with two response formats
- localStorage
- Known limitations and common mistakes
llms.txt— quick index for AI assistants- Voice → Serial Bluetooth Tutorial — speech recognition with 22 languages
window.soifgo is undefined. Always guard with if (window.soifgo) { ... }.
2. Bluetooth
Send to Bluetooth
window.soifgo.CallSub('html_bluetooth_rx', true, message);
The second argument is the return flag — always true. The third argument is the data (text/message) to send.
Receive from Bluetooth
function html_bluetooth_tx(data) {
// data = string from the device
}
window.html_bluetooth_tx = html_bluetooth_tx; // must be on window
window.soifgo.CallSub('html_bluetooth_rx', true, 'LED_ON');
3. Phone Sensors
Three sensors available: Light, Movement (X/Y), Magnetic field.
Activate (in window.onload)
window.soifgo.CallSub('sensor_light', true);
window.soifgo.CallSub('sensor_move', true);
window.soifgo.CallSub('sensor_magno', true);
Receive (register each on window)
function html_sensor_light(data) { /* light value */ }
function html_sensor_movex(data) { /* move X */ }
function html_sensor_movey(data) { /* move Y */ }
function html_sensor_magno(data) { /* magnetic */ }
window.html_sensor_light = html_sensor_light;
window.html_sensor_movex = html_sensor_movex;
window.html_sensor_movey = html_sensor_movey;
window.html_sensor_magno = html_sensor_magno;
4. MQTT
Built-in MQTT client — no WebSocket, no CORS, no external library. Only works inside SoifGo.
Connect — step 1: broker + client ID
window.soifgo.CallSub('connecte_mqtt_ai', true, address, id);
// address : "tcp://host:1883" or "ssl://host:8883"
// Empty → defaults to test.mosquitto.org:1883
// id : unique string. Empty → auto-generated
Connect — step 2: auth (optional)
window.soifgo.CallSub('connecte_mqtt_up', true, username, password);
Publish (also auto-subscribes to that topic)
window.soifgo.CallSub('mqtt_publish', true, topic, message, qos);
// qos : "0", "1", or "2" as a STRING
Disconnect / Check status
window.soifgo.CallSub('mqtt_Disconnect', true);
window.soifgo.CallSub('mqtt_status', true);
// SoifGo replies by calling html_mqtt_status('true' or 'false')
Receivers
function mqtt_rx(topic, message) { /* incoming message */ }
window.mqtt_rx = mqtt_rx;
function html_mqtt_status(connected) {
// ⚠️ value arrives as a STRING ('true' / 'false')
const isConnected = (connected === true || connected === 'true');
}
window.html_mqtt_status = html_mqtt_status;
mqtt_publish also subscribes you to that topic — so you'll receive messages published to it by other clients.
- Leave client ID empty → unique ID auto-generated.
- Status arrives as a string — always compare with
=== 'true'. - Topic names are case-sensitive.
5. REST API
Built-in HTTP bridge — no fetch, no CORS, no library.
Send (POST)
window.soifgo.CallSub('api_send', true, address, key, value);
// POST
// Body: {"":""} Content-Type: application/json
Receive (GET)
window.soifgo.CallSub('api_recive', true, address, key);
// GET
// SoifGo extracts the value at and calls api_rx()
Receiver
function api_rx(value) {
// value arrives as a string
}
window.api_rx = api_rx;
⚠️ Two response formats — handle both
| Format | Raw JSON | api_rx receives |
|---|---|---|
| A — flat (e.g. DIA) | {"Price": 86846.5} |
"86846.5" |
| B — nested (e.g. CoinGecko) | {"bitcoin":{"usd":86750}} |
"{usd=86750}" |
Robust extractor (copy-paste)
function extractValue(raw, fieldName) {
const s = String(raw).trim();
// 1. plain number: "86846.5"
if (/^-?\d+(\.\d+)?$/.test(s)) return s;
// 2. B4A Map: "{usd=86750}" or "{Price=86846.5}"
const m = s.match(new RegExp(fieldName + '[=:]\\s*([^,}\\s]+)', 'i'));
if (m) return m[1];
// 3. JSON: {"usd":86750}
try {
const o = JSON.parse(s);
if (o[fieldName] !== undefined) return o[fieldName];
} catch (e) {}
// 4. fallback: any number
const n = s.match(/-?\d+(\.\d+)?/);
return n ? n[0] : null;
}
6. Storage (localStorage)
Standard localStorage works inside SoifGo's WebView. Data persists across page reloads and WebView restarts.
// save
localStorage.setItem('my_key', JSON.stringify(data));
// load
const data = JSON.parse(localStorage.getItem('my_key')) || [];
// clear
localStorage.removeItem('my_key');
alert(), confirm(), and prompt() all work natively in SoifGo's WebView — no custom modal needed.
- Wrap storage calls in
try/catchto handle quota errors. - Use unique keys per page (e.g.
'page1_data'). - Always escape user input before injecting into
innerHTML(XSS guard).
7. Full API Reference
Every Sub call and callback available in SoifGo's WebView layer.
Subs — send / activate
| Call | Type | Description |
|---|---|---|
html_bluetooth_rx(newline, msg) |
SEND | Send string to Bluetooth. newline = true/false. |
sensor_light |
ACT | Activate ambient light sensor stream. |
sensor_move |
ACT | Activate accelerometer (X/Y) stream. |
sensor_magno |
ACT | Activate magnetic field sensor stream. |
request_mic_perm |
ACT | Request microphone permission (first time only). |
connecte_mqtt_ai(address, id) |
SEND | MQTT connect step 1 — broker URL + client ID. |
connecte_mqtt_up(user, pass) |
SEND | MQTT connect step 2 — username + password (optional). |
mqtt_publish(topic, msg, qos) |
SEND | Publish message. Also subscribes to the same topic. |
mqtt_status |
SEND | Query connection status → replies via html_mqtt_status. |
mqtt_Disconnect |
SEND | Disconnect from the broker. |
api_send(address, key, value) |
SEND | HTTP POST — sends JSON {"key":"value"}. |
api_recive(address, key) |
SEND | HTTP GET — extracts value at key → calls api_rx. |
Callbacks — SoifGo calls your page
| Function | Type | Receives |
|---|---|---|
html_bluetooth_tx(data) |
RECV | Incoming Bluetooth string. |
html_sensor_light(data) |
RECV | Light sensor value. |
html_sensor_movex(data) |
RECV | Movement X value. |
html_sensor_movey(data) |
RECV | Movement Y value. |
html_sensor_magno(data) |
RECV | Magnetic field value. |
mqtt_rx(topic, message) |
RECV | Incoming MQTT message on a subscribed topic. |
html_mqtt_status(connected) |
RECV | MQTT status as a string ('true' / 'false'). |
api_rx(value) |
RECV | API response — plain number or B4A Map string. |
window object: window.api_rx = api_rx;
8. Working Examples
Copy-ready pages — open the live demo, view the code, and grab the Arduino sketch where relevant.
9. Troubleshooting
window.soifgo is undefined, you're in a normal browser. The bridge only exists inside SoifGo.
window: window.api_rx = api_rx;
=== 'true', not === true.
extractValue() helper above.
request_mic_perm before using getUserMedia or SpeechRecognition. The user must allow it once.