Skip to content

Hotspot API Server

Calin Crisan edited this page Dec 2, 2021 · 57 revisions

Table Of Contents

About

The Hotspot API Server is a small webserver written in Python that exposes an API dedicated to remote controlling the Chameleon OS.

The server lives at /opt/hotspot-api-server.

Authentication

Each request that requires authentication, must include an Authorization header containing HTTP basic auth data:

Authorization: Basic BASE64(<username:password>)

There are two defined usernames:

  • admin - works with user-configurable password and the default password is admin.

  • dashboard - for internal purposes, works with a password obtained as follows:

    SHA256(<hostname>:<wlan_mac>:<pub_key_hex>:<ecc_sn>)
    

    All hex digits are lowercase.

API Calls

GET /summary

Returns a summary of the current hotspot state. Does not require authentication. Response body looks like this:

{
    "serial_number": "11068ec1",
    "os_prefix": "cham",
    "cpu_usage": 60, /* percent */
    "mem_used": 150, /* MB */
    "mem_total": 7192, /* MB */
    "swap_used": 250, /* MB */
    "swap_total": 2048, /* MB */
    "storage_used": 58686, /* MB */
    "storage_total": 3205, /* MB */
    "temperature": 47, /* C */
    "miner_height": 762332,
    "miner_listen_addr": "/ip4/79.141.2.132/tcp/44158",
    "miner_listen_ok": true,
    "hotspot_name": "magnificent-midnight-wolf",
    "concentrator_model": "sx1302",
    "region": "EU868",
    "fw_version": "2021.03.09.0",
    "ecc_sn": "0123104236962a42ee",
    "swarm_key_mode": false,
    "address": "112axoWXqxrdT5Gd56iz7Mychkt9UU3EV3d9krTnkrLvodjJRYC2",
    "pub_key": "d0cfaae2f6157e55978e8a715a5117cd7a23b766d4419b762402d8de4839e0f8212a0c5120deca00c616fb1125617e8d7f6e47adff213349efc949735809d788",
    "eth_mac": "dc:a6:32:ad:aa:ff",
    "wlan_mac": "dc:a6:32:ad:ab:00",
    "bt_mac": "dc:a6:32:ad:ab:01",
    "uptime": 86400, /* seconds */
    "time": 1622664430 /* Unix timestamp, in seconds */,
    "last_panic": { /* null if no panic within last 12h */
        "service": "packetforwarder",
        "message": "no region information",
        "timestamp": 1634447900,
        "uptime": 7436
    },
    "current_state": "lora_ready"  /* powered_up|ip_ready|miner_syncing|lora_ready|updating_firmware|no_net|panic|rebooting */
}

If the pretty=true query argument is passed, field names and their values are prepared for pretty printing.

If the quick=true query argument is passed, only values for fields that are immediately available will be returned.

GET /nettest

Performs a quick network connection analysis and returns the results. Does not require authentication. Response body looks like this:

{
    "download_speed": 2505, /* kBytes/s */
    "latency": 11, /* milliseconds */
    "public_ip": "79.114.24.84",
    "sb_api_reachable": true,
    "helium_api_reachable": true
}

If the pretty=true query argument is passed, field names and their values are prepared for pretty printing.

GET /troubleshoot

Performs self diagnosis and returns the results. Requires authentication.

Response body looks like this:

{
    "hardware": {
        "ethernet_present": true,
        "wifi_present": true,
        "bluetooth_present": true,
        "concentrator_present": false,
        "ecc_present": true,
        "ecc_provisioned": true
    },
    "network": {
        "download_speed": 3037,
        "latency": 24,
        "sb_api_reachable": true,
        "helium_api_reachable": true
    },
    "miner": {
        "ping": "true,
        "region_ok": false,
        "listening": true,
        "reachable": true,
        "direct": false
    }
}

If the pretty=true query argument is passed, field names and their values are prepared for pretty printing.

GET /stats

Returns some stats about the hotspot. Does not require authentication. Response body looks like this:

{
    "blockchain_height": 862332,
    "rewards_1d": 8.32, /* HNT */
    "rewards_7d": 58.24, /* HNT */
    "rewards_30d": 249.6, /* HNT */
    "rewards_365d": 3036.8, /* HNT */
    "oracle_price": 14.123456 /* USD */
}

GET /activity

Returns the hotspot's recent activity. Does not require authentication. Response body looks like this:

[
    {
        "block": 868235,
        "time": 1622628182,
        "amount": 1974,
        "type": "rewards_v2"
    },
    ...
]

GET /peers/book

Returns the miner's peers book. Does not require authentication. Response body looks like this:

[
    {
        "local": "/ip4/192.168.1.234/tcp/44158",
        "remote": "/ip4/13.83.228.67/tcp/44159",
        "p2p": "/p2p/1129rTuZbPA8fg1mc4TXbRfVa5QDb4UNj3P1o14N92WVMSVa46bU",
        "address": "1129rTuZbPA8fg1mc4TXbRfVa5QDb4UNj3P1o14N92WVMSVa46bU",
        "name": "big-grape-beaver"
    },
    ...
]

GET /peers/ping

Pings a peer and returns the round-trip time. Does not require authentication.

Query argument address is required and represents the peer's address (e.g. 1129rTuZbPA8fg1mc4TXbRfVa5QDb4UNj3P1o14N92WVMSVa46bU).

Response body looks like this:

{
    "round_trip_time": 235 /* or null if ping failed */
}

GET /peers/connect

Attempts to connect to a peer and returns the status. Does not require authentication.

Query argument address is required and represents the peer's address (e.g. 1129rTuZbPA8fg1mc4TXbRfVa5QDb4UNj3P1o14N92WVMSVa46bU).

Response body looks like this:

{
    "success": true
}

POST /peers/reset

Resets the peers book and restarts the miner. Requires authentication.

Response body is empty.

GET /config

Returns the current configuration. Requires authentication. Response body looks like this:

{
    "cpu_freq_max": 1500000, /* in kHz, null means default */
    "led_brightness": 50, /* from 0 to 100 */
    "led_ok_color": "green", /* red, green, blue, yellow, cyan, magenta, orange, white, off */
    "network_type": "wifi", /* wifi, ethernet */
    "network_ssid": "My Network 1", /* can be null */
    "nat_external_ip": "72.012.123.234", /* can be null */
    "nat_external_port": 44159, /* can be null */
    "nat_internal_port": 44158, /* can be null */
    "panic_on_relayed": false,
    "panic_on_unreachable": false,
    "force_sync_enabled": true,
    "periodic_reset_peers": false,
    "pf_antenna_gain": 2.3, /* dBi */
    "pf_rssi_offset": -215.4, /* dBm */
    "pf_tx_power": 14 /* dB */,
    "remote_enabled": true,
    "external_wifi_antenna": true,
    "periodic_reboot": true
}

PATCH /config

Updates the configuration. Requires authentication. Request body looks like this:

{
    "cpu_freq_max": 1500000, /* in kHz, null means default */
    "led_brightness": 50, /* from 0 to 100 */
    "led_ok_color": "green", /* red, green, blue, yellow, cyan, magenta, orange, white, off */
    "network_type": "wifi", /* wifi, ethernet */
    "network_ssid": "My Network 1", /* ignored when network_type != wifi */
    "network_psk": "deadbeef", /* ignored when network_type != wifi */
    "nat_external_ip": "72.012.123.234", /* null disables */
    "nat_external_port": 44159, /* null disables */
    "nat_internal_port": 44158, /* null disables */
    "panic_on_relayed": false,
    "panic_on_unreachable": false,
    "force_sync_enabled": true,
    "periodic_reset_peers": false,
    "pf_antenna_gain": 2.3, /* dBi */
    "pf_rssi_offset": -215.4, /* dBm */
    "pf_tx_power": 14, /* dB */
    "password": "password1234",
    "old_password": "password123",
    "remote_enabled": true,
    "external_wifi_antenna": true,
    "periodic_reboot": true
}

All fields are optional. If a field is given as null, it will be restored to its default value.

If password is supplied, an additional old_password field must be included as well and must contain the current password.

GET /networks

Returns available networks. Requires authentication. Response body looks like this:

{
    "ethernet": true,
    "wifi": [
        "My Network 1",
        "Neighbor's Network 2",
        ...
    ]
}

POST /verify_password

Verifies a given password. Request body looks like this:

{
    "password": "password1234"
}

Returns 204 if password is valid and 200 (with a result message) otherwise.

POST /reset_password

Resets the device password.

If request body is empty (first part of the reset flow), the unit will generate a random code and will set LED strip colors using an associated pattern. The code is made up of the first lowercase letter of each of the available colors: [r]ed, [g]reen, [b]lue, [c]yan, [m]agenta, [y]ellow, [o]range and [w]hite.

To set a new password (second part of the reset flow), request body should look like:

{
    "code": "rgbcmy",
    "password": "my_new_password"
}

An invalid code will result in a 403 status code and a 2 seconds delay. A valid code will result in a 204 and the admin password will be set to the supplied one.

The generated code expires in 60 seconds. The LED strip will return to normal at the end of the password reset flow.

POST /reboot

Reboots the unit. Requires authentication.

POST /pair

Enables temporary unit pairing mode. Requires authentication.

POST /resync

Forces a miner resynchronization. Requires authentication.

POST /txn/add_gateway

Pushes an add_gateway transaction to the miner, returning the base64-encoded transaction. Requires authentication.

Request body looks like this:

{
    "owner": "12ySLkgCNJHkvGg7G9jiq1PE7Dm691H8aSjex8xMR5Pwtic9XV6",
    "payer": "14rb2UcfS9U89QmKswpZpjRCUVCVu1haSyqyGY486EvsYtvdJmR"
}

Response body looks like this:

CpYBCiEBA9fOirleO0dNfigK0zBn/PDeCLnXsx4fB5nDanX46tgSIQDQz6ri9hV+VZeOinFaURfNeiO3ZtRBm3YkAtjeSDng+CJGMEQCIF0WfBAH8Xt0CcQjUXJVf9Bb4ScOGWD63kCNLXo1+3n9AiAVTNjy395sKDsp6+zIDA7CRVHbE1Xl+KCStoC8IQ4SpzjAhD1AyN8C

POST /txn/assert_location

Pushes an assert_location transaction to the miner, returning the base64-encoded transaction. Requires authentication.

Request body looks like this:

{
    "owner": "12ySLkgCNJHkvGg7G9jiq1PE7Dm691H8aSjex8xMR5Pwtic9XV6",
    "payer": "14rb2UcfS9U89QmKswpZpjRCUVCVu1haSyqyGY486EvsYtvdJmR",
    "location": "45.12345,21.23456",
    "nonce": 1
}

nonce is optional and defaults to 1.

Response body looks like this:

CpYBCiEBA9fOirleO0dNfigK0zBn/PDeCLnXsx4fB5nDanX46tgSIQDQz6ri9hV+VZeOinFaURfNeiO3ZtRBm3YkAtjeSDng+CJGMEQCIF0WfBAH8Xt0CcQjUXJVf9Bb4ScOGWD63kCNLXo1+3n9AiAVTNjy395sKDsp6+zIDA7CRVHbE1Xl+KCStoC8IQ4SpzjAhD1AyN8C

GET /fwupdate

Returns information about the currently running and latest firmware version. Requires authentication.

Response body looks like this:

{
    "current": "2021.07.09.0",
    "latest": "2021.07.09.0",
    "beta": false,
    "status": "idle"
}

Possible statuses are: idle, downloading, extracting, flashing boot, rebooting.

PATCH /fwupdate

Starts the firmware upgrade process. Requires authentication.

GET /logs/{name}

Returns the log indicated by name. Requires authentication.

If the optional max_lines query argument is supplied, the last indicated number of lines are returned (defaults to 1000).

The following logs are defined:

  • miner (/var/log/miner/console.log)
  • packet_forwarder (/var/log/packet_forwarder.log)
  • kernel (dmesg)
  • system (/var/log/messages)

POST /logs/start

Starts sending logs via MQTT. Logs will be sent until explicitly stopped or the unit is rebooted. Requires authentication.

See Logs Via MQTT.

POST /logs/stop

Stops sending logs via MQTT. See Logs Via MQTT. Requires authentication.

{method} /sbapi/{path...}

Performs a SB API passthrough request, adding the required Authorization header. Requires authentication.

Clone this wiki locally