SoifGo Logo SoifGo

Developer Documentation

One-page API reference: Bluetooth, MQTT, sensors, REST APIs, and storage — all in window.soifgo.CallSub().

← Back to main page

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)
💡 Bridge rules:
  • Second argument is always a boolean (true or false).
  • 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.

🤖 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
💡 What it covers:
  • 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
📄 Also available:
⚠️ The bridge only exists inside SoifGo's WebView. In a normal browser, 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
💡 Example: 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;
✅ Done. The page receives continuous real-time sensor data.

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;
⚠️ Important: mqtt_publish also subscribes you to that topic — so you'll receive messages published to it by other clients.
💡 Tips:
  • 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}"
⚠️ Always use a robust extractor that handles both — plain numbers, B4A Map strings, and JSON.

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;
}
💡 Rate limits — always add a Stop button. Safe polling intervals: DIA 5s · CoinGecko 10s · Binance 1s · Coinbase 5s · Blockchain.info 10s.

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.
💡 Best practices:
  • Wrap storage calls in try/catch to 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.
⚠️ All callbacks must be registered on the 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

Bridge not found — if window.soifgo is undefined, you're in a normal browser. The bridge only exists inside SoifGo.
Callback never fires — make sure it's on window: window.api_rx = api_rx;
MQTT status always "connected" — the value is a string. Compare with === 'true', not === true.
MQTT messages not arriving — publish at least once to the topic (auto-subscribes). Check case sensitivity.
API response parse fails — the value may be a plain number or a B4A Map string. Use the extractValue() helper above.
Rate limit (HTTP 429) — increase the polling interval. See Rate Limits in section 5.
Microphone permission denied — call request_mic_perm before using getUserMedia or SpeechRecognition. The user must allow it once.