# RF Link Budget Calculator (LoRa, Wi-Fi, Microwave, Satellite) (`jumblemog/rf-link-budget-calculator`) Actor

Radio link budgets from plain text: path loss (free space, two-ray, Hata, satellite), ITU-R rain and gas loss, received power, SNR, Eb/N0, fade margin, max range and Fresnel clearance. For AI agents.

- **URL**: https://apify.com/jumblemog/rf-link-budget-calculator.md
- **Developed by:** [Jumble Mog](https://apify.com/jumblemog) (community)
- **Categories:** AI, Automation, Developer tools
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## RF Link Budget Calculator (LoRa, Wi-Fi, Microwave, Satellite)

**Will this radio link work? Describe it in one line and find out.** Type `LoRa SF12 at 868 MHz, 14 dBm, 2 dBi antennas, 15 km, rural` or `5.8 GHz, 10 km, 23 dBm, 30 dBi dishes both ends, sensitivity -80 dBm, 99.99% at 40.4, -3.7`. You get back:

- **The whole budget**, step by step: transmit power, antenna gains, cable losses, EIRP, path loss, the weather losses, and the received power in dBm and watts.
- **The receiver side**: the noise floor, SNR, C/N0, Eb/N0 and Shannon capacity. You can give a sensitivity or let the tool work it out from the noise figure, bandwidth and required SNR.
- **The verdict**: the link margin, whether it keeps the fade margin you want (10 dB unless you say otherwise), and the transmit power that margin needs.
- **The range**: how far the link reaches with that margin, and at bare sensitivity.
- **The clearance**: the first Fresnel zone, the earth bulge, the height the path needs above obstacles, and the radio horizon for your antenna heights.
- **A chart**: the budget as a waterfall, and the received power against distance with the sensitivity and margin lines.

Propagation models:

- **Free space** (Friis, ITU-R P.525), the default.
- **Two-ray ground reflection**, for low antennas over flat ground.
- **Log-distance** with an exponent, for indoor and cluttered paths.
- **Okumura-Hata** (150-1500 MHz) and **COST-231 Hata** (1500-2000 MHz) for urban, suburban and rural cells. These are picked by themselves when you name the environment.
- **Satellite slant paths** for GEO, MEO and LEO: the slant range from the elevation and orbit, plus gases, clouds, rain and scintillation by ITU-R P.618.

Weather comes from the ITU-R models when it matters:

- **Atmospheric gases** (ITU-R P.676) from 10 GHz, so 24, 60 and 80 GHz links carry their oxygen and water-vapour loss.
- **Rain** for an availability such as `99.99%`. On terrestrial paths it uses ITU-R P.530 with P.838, and the rain rate comes from the ITU-R P.837 world maps for your coordinates (or a rate you give).

It's made for:

- IoT and LoRa/LoRaWAN/Meshtastic builders planning gateway coverage.
- WISPs and network engineers sizing point-to-point microwave hops.
- Ham radio operators, drone and RC pilots, and students.
- Satellite ground-station planners.
- AI agents that need a real dB answer instead of a guess.

![A LoRa SF12 link at 868 MHz over 15 km rural, computed by this Actor: the budget waterfall from 14 dBm to -119.8 dBm received, and the received power by distance crossing the -137 dBm sensitivity at 46 km and the 10 dB margin line at 24 km](https://api.apify.com/v2/key-value-stores/Km5b4PG3kYHdZSb1E/records/rf-link-budget-calculator-example.png?signature=1vQpV9lIqQMPa7H48COpO)

### How to use it

1. Write **Links**, one per line, such as `2.4 GHz, 3 km, 20 dBm, 12 dBi antennas, sensitivity -85 dBm`. The form has examples.
2. Optionally set a **Default fade margin**, **Default propagation model** or **Default noise figure**.
3. Click **Start**. Each link is a row in the results, with its summary, chart and report.

#### Writing links

A line can hold any of these, in any order:

- **Frequency**: `868 MHz`, `5.8 GHz`.
- **Distance**: `15 km`, `300 m`, `2 mi`. Satellite links can give the elevation instead.
- **Power**: `14 dBm`, `30 W`, `500 mW`, or `EIRP 52 dBW`.
- **Antennas**:
  - Gains: `2 dBi antennas` (both ends), `tx antenna 12 dBi`, `rx 3 dBi`.
  - Dishes: `0.6 m dish`, `30 dBi dishes both ends`.
- **Losses**: `1 dB cable loss each end`, `3 dB body loss`, `10 dB foliage loss`.
- **Heights**: `gateway height 30 m`, `node height 2 m`, `base station 50 m`, `mobile 1.5 m`.
- **Model**: `urban`, `suburban`, `rural`, `indoor`, `two-ray`, `path loss exponent 3`, `free space`.
- **Receiver**:
  - `sensitivity -110 dBm`.
  - Or `NF 6 dB`, `125 kHz bandwidth` and `SNR 10 dB`.
  - Or `Eb/N0 6 dB at 40 Mbps`.
  - Or a LoRa spreading factor: `SF7` to `SF12` (125 kHz and the Semtech SNR limits).
- **Margin**: `15 dB fade margin`.
- **Weather and place**: `99.99% availability`, `at 40.4, -3.7`, `42 mm/h`, `vertical polarization`.
- **Satellite**: `GEO`, `LEO 550 km`, `elevation 30°`, `downlink`, `G/T 12 dB/K`.

Objects work too, with the same fields named; see Input.

### Examples

All of these ran on this Actor; the numbers are from the results.

| Link | Result |
|---|---|
| `LoRa SF12 at 868 MHz, 14 dBm, 2 dBi antennas, 15 km, rural, gateway height 30 m, node height 2 m` | Hata rural path loss 137.8 dB, received -119.8 dBm against a -137 dBm sensitivity: 17.2 dB margin. 24 km range with a 10 dB margin, 46 km at bare sensitivity |
| `5.8 GHz point-to-point, 10 km, 23 dBm, 30 dBi dishes both ends, 1 dB cable loss each end, sensitivity -80 dBm, tower height 25 m, 99.99% availability at 40.4, -3.7` | EIRP 52 dBm, 0.58 dB of rain at 99.99% in Madrid, received -47.3 dBm, 32.7 dB margin. Line of sight ends at 41 km for 25 m towers |
| `12 GHz GEO downlink, EIRP 52 dBW, 0.6 m dish, elevation 30°, at 51.5, -0.1, 99.9%, 27 MHz bandwidth, noise figure 1 dB, Eb/N0 6 dB at 40 Mbps` | 38,600 km slant range, 205.8 dB free-space loss plus 2.3 dB of gases, clouds, rain and scintillation in London. Eb/N0 10.8 dB, 4.8 dB margin |
| `900 MHz, 30 W, base station 50 m, mobile 1.5 m, 8 km, urban, 15 dBi tx antenna, 0 dBi rx antenna, sensitivity -104 dBm` | Okumura-Hata urban loss 153.8 dB, 9.9 dB margin, 7.96 km range with a 10 dB margin |
| `60 GHz, 1 km, 10 dBm, 38 dBi, sensitivity -65 dBm` | 14.8 dB of oxygen absorption on top of 128 dB free-space loss, 8.2 dB margin |
| `433 MHz, 10 mW, 2 km, two-ray, tx height 3 m, rx height 1 m, NF 6 dB, 25 kHz bandwidth, SNR 10 dB` | Two-ray loss 122.5 dB (31 dB over free space), noise floor -124 dBm, SNR 11.5 dB, 1.5 dB margin |

The tests check that:

- Free-space loss matches 32.45 + 20 log f(MHz) + 20 log d(km).
- Okumura-Hata matches the hand calculation, and two-ray matches the plane-earth formula past the crossover.
- The noise floor is -174 dBm/Hz at 290 K, and LoRa sensitivities match Semtech's (-137 dBm at SF12, -124.5 dBm at SF7).
- Dish gain, the Fresnel radius (17.32 √(d/4f)), the 4/3-earth radio horizon and the slant range match their formulas.
- Rain and oxygen losses fall in their known ranges.
- Range and required power follow from the margin.

### How-to examples

Each example is a complete input; the results are from runs of the Actor (also listed under **Examples**).

#### How to calculate a LoRa link budget and range

```json
{"links": ["LoRa SF12 at 868 MHz, 14 dBm, 2 dBi antennas, 15 km, rural, gateway height 30 m, node height 2 m"]}
```

Result: Hata rural path loss 137.8 dB, received -119.8 dBm against a -137 dBm sensitivity: a 17.2 dB margin. The range is 24 km with a 10 dB margin, 46 km at bare sensitivity.

#### How to check a microwave point-to-point link with rain fade

```json
{"links": ["5.8 GHz point-to-point, 10 km, 23 dBm, 30 dBi dishes both ends, 1 dB cable loss each end, sensitivity -80 dBm, tower height 25 m, 99.99% availability at 40.4, -3.7"]}
```

Result: EIRP 52 dBm, 0.58 dB of rain at 99.99% in Madrid, received -47.3 dBm and a 32.7 dB margin. Line of sight ends at 41 km for 25 m towers.

#### How to calculate a satellite downlink budget

```json
{"links": ["12 GHz GEO downlink, EIRP 52 dBW, 0.6 m dish, elevation 30°, at 51.5, -0.1, 99.9%, 27 MHz bandwidth, noise figure 1 dB, Eb/N0 6 dB at 40 Mbps"]}
```

Result: 38,600 km slant range, 205.8 dB free-space loss plus 2.3 dB of gases, clouds, rain and scintillation in London; Eb/N0 10.8 dB, a 4.8 dB margin.

#### How to let an AI agent check radio links

Add this Actor to the [Apify MCP server](https://mcp.apify.com) with `https://mcp.apify.com/?tools=jumblemog/rf-link-budget-calculator`. The agent describes the link in one line and answers with the path loss, received power, margin and range.

### FAQ

**Which propagation models does it use?** Free space, two-ray, log-distance, Okumura-Hata, COST 231 and satellite paths, picked from the line or set with `model`; the Hata models never go below free space.

**Does it include rain and atmospheric loss?** Yes, by ITU-R: gases by P.676, terrestrial rain by P.530 with the P.837 rain rate at your coordinates, and satellite paths by P.618.

**Does it know LoRa sensitivities?** Yes. Give `SF7` to `SF12` and it uses 125 kHz and Semtech's SNR limits (-137 dBm at SF12, -124.5 dBm at SF7).

**Does it check Fresnel clearance?** Yes: the first Fresnel zone and earth bulge mid-path with k = 4/3, and the radio horizon from both antenna heights.

### Input

| Field | What it is |
|---|---|
| `links` | Links, as text lines or objects. |
| `fadeMargin`, `model`, `noiseFigure` | Defaults for links that don't give them. |
| `charts` | Draw charts (default on). |

**A link as an object** takes:

- **Radio**: `frequency`; `distance` (a number is km); `txPower` or `eirp`.
- **Antennas**: `txGain`, `rxGain` or `antennaGain` (both ends); `txDish`, `rxDish` or `dish` (diameter, 60% efficiency unless you give `dishEfficiency`).
- **Losses**: `txLoss`, `rxLoss` or `cableLoss` (each end); `otherLosses`.
- **Path**: `model` (`free-space`, `two-ray`, `log-distance`, `hata`, `cost231`, `satellite`); `environment` (`urban`, `dense urban`, `suburban`, `rural`, `indoor`); `pathLossExponent`; `txHeight`, `rxHeight` (m); `kFactor` (default 4/3).
- **Receiver**:
  - `sensitivity`;
  - or `noiseFigure`, `bandwidth` and `requiredSnr`;
  - or `requiredEbN0` and `dataRate`;
  - or `loraSf`.
  - Also `antennaTemperature` and `gOverT`.
- **Margin**: `fadeMargin` (default 10 dB).
- **Weather**: `availability` or `timePercentage`; `latitude`, `longitude`; `rainRate` (mm/h at 0.01%); `polarization`; `gases`, `humidity`, `temperature`, `pressure`.
- **Satellite**: `elevation`; `orbit` (`GEO`, `MEO`, `LEO` or an altitude); `direction` (`downlink` uses a 50 K sky temperature).
- **Other**: `title`, and `text` (a line to start from, which the other fields override).

### Output

One dataset item per link, also saved together in the run's `OUTPUT` record:

```json
{
  "request": 1, "status": "ok", "type": "link",
  "title": "LoRa SF12 868 MHz link over 15 km",
  "summary": "LoRa SF12 868 MHz link over 15 km: EIRP 16 dBm, path loss 137.8 dB, received -119.8 dBm, SNR -2.8 dB; margin 17.2 dB, which closes with 7.2 dB to spare over the 10 dB fade margin wanted. Range with that margin: 24 km.",
  "link": {"frequencyMHz": 868.0, "wavelength": 0.3454, "distanceKm": 15.0, "model": "hata", "environment": "rural",
           "txHeight": 30.0, "rxHeight": 2.0},
  "budget": {"txPower": 14.0, "txAntennaGain": 2.0, "eirp": 16.0, "pathLoss": 137.8, "freeSpaceLoss": 114.74,
             "gases": 0.0, "rain": 0.0, "rxAntennaGain": 2.0, "totalPathLoss": 137.8, "receivedPower": -119.8},
  "receiver": {"sensitivity": -137.01, "sensitivityBasis": "noise floor + required SNR", "noiseFloor": -117.01,
               "bandwidth": 125000.0, "snr": -2.8, "requiredSnr": -20.0, "cn0": 48.17, "loraSpreadingFactor": 12},
  "margin": {"linkMargin": 17.2, "fadeMarginTarget": 10.0, "closes": true, "requiredTxPower": 6.8,
             "maxRangeKm": 24.02, "rangeAtSensitivityKm": 46.18, "lineOfSightLimitKm": 28.41},
  "geometry": {"fresnelRadius": 35.99, "clearance60": 21.59, "earthBulge": 3.31, "clearanceAboveObstacles": 24.9,
               "radioHorizonKm": 28.41, "beyondHorizon": false},
  "imageUrl": "https://api.apify.com/v2/key-value-stores/.../records/001-....png"
}
```

Powers are in dBm, gains in dBi, losses in dB, distances in km and heights in m (see `unitLabels`). For satellite links `geometry` holds the elevation, slant range and orbit altitude. A link that can't be computed has `"status": "failed"` and the reason in `error`, and isn't billed.

### How it works

1. **Reading the link**: the line is split into its parts, and units are converted (W to dBm, miles to meters, dish diameter to gain).
2. **Path loss** by the model, never below free space for the Hata models.
3. **Weather**:
   - Gases by ITU-R P.676 from 10 GHz.
   - Terrestrial rain by ITU-R P.530 for the time percentage, with P.838 specific attenuation and the P.837 rain rate at your coordinates.
   - Satellite paths by ITU-R P.618: gases, clouds (P.840), rain and scintillation. All of these use the [itur](https://github.com/inigodelportillo/ITU-Rpy) library.
4. **Received power** = EIRP − losses + receive gain − receive cable loss.
5. **Noise floor** = k·T·B, where T is the antenna temperature plus 290 K × (F − 1). The sensitivity is that floor plus the required SNR, or the value you give.
6. **Range**: the distance where the received power meets sensitivity plus the fade margin, found by root-finding on the same model with the weather recomputed at each distance.
7. **Clearance**: the first Fresnel zone and earth bulge mid-path (k = 4/3), and the radio horizon from both antenna heights.
8. **Charts** are drawn with Vega-Lite and rendered with vl-convert.

### Pricing

You pay one low price per link, at the price shown on this page. It includes the chart and the report. Links that can't be computed are never charged. If you set a maximum cost per run, the Actor stops before a link that wouldn't fit.

### Speed

Each link takes a few milliseconds plus its chart. A link with ITU-R weather takes up to about a second more, the first time the maps load. A run through the API answers in about 10 to 15 seconds, including the cloud container starting.

### Tips and limits

- **These are planning numbers.** Models give median losses. They don't see your terrain, buildings or trees, so leave margin. Hata in particular is only fitted for 1-20 km and 30-200 m base stations, and the result warns when you're outside that range.
- **Line of sight**: give antenna heights to have the radio horizon and Fresnel clearance checked. Without them, the horizon assumes 10 m at both ends and no clearance warning is raised.
- **Not included**: terrain profiles and diffraction over real obstacles, multipath fading statistics, interference, and the satellite's own transponder noise (C/N here is the single hop you describe).
- **Rain** needs coordinates or a rain rate; availability is 95% to 99.999%.
- **Limits**: 500 links per run.

### For AI agents and developers

This Actor works with the [Apify MCP server](https://mcp.apify.com), so AI agents can call it as a tool. Pass `links` as plain text and read `summary`, `margin.linkMargin`, `margin.closes`, `margin.maxRangeKm` and `budget.receivedPower`. A direct API call that waits for the answer:

```bash
curl -X POST "https://api.apify.com/v2/acts/jumblemog~rf-link-budget-calculator/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"links": ["LoRa SF10 at 915 MHz, 20 dBm, 3 dBi antennas, 8 km, suburban, gateway height 40 m"]}'
```

`run-sync` instead returns the run's `OUTPUT`: the status, the counts and every result as JSON.

In Python, with the `apify-client` package:

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_TOKEN")
run = client.actor("jumblemog/rf-link-budget-calculator").call(run_input={
    "links": [{"frequency": "24 GHz", "distance": 3, "txPower": "10 dBm", "antennaGain": "34 dBi",
               "sensitivity": "-70 dBm", "availability": "99.99%", "latitude": 1.35, "longitude": 103.8}],
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["summary"])
```

### Credits

- Weather models: [ITU-Rpy](https://github.com/inigodelportillo/ITU-Rpy) (MIT) by Iñigo del Portillo, implementing ITU-R P.453, P.530, P.618, P.676, P.836, P.837, P.838, P.839 and P.840.
- Root-finding: [SciPy](https://scipy.org) (BSD-3-Clause).
- Charts: [Vega-Lite](https://vega.github.io/vega-lite/) and [vl-convert](https://github.com/vega/vl-convert) (BSD-3-Clause), with the [Inter](https://rsms.me/inter/) font (SIL Open Font License).
- Models: Friis (1946); Hata, *Empirical formula for propagation loss in land mobile radio services* (1980); COST 231 final report (1999); ITU-R P.525; LoRa SNR limits from the Semtech SX1276 datasheet.

# Actor input Schema

## `links` (type: `array`):

One link per entry, as a line of text or an object. Text: 'LoRa SF12 at 868 MHz, 14 dBm, 2 dBi antennas, 15 km, rural', '5.8 GHz, 10 km, 23 dBm, 30 dBi dishes both ends, sensitivity -80 dBm, 99.99% at 40.4, -3.7', '12 GHz GEO downlink, EIRP 52 dBW, 0.6 m dish, elevation 30°'. Object fields: frequency, distance (numbers in km), txPower (dBm, dBW or W) or eirp, txGain, rxGain or antennaGain (dBi), txDish/rxDish (diameter), txLoss, rxLoss or cableLoss, otherLosses, model (free-space, two-ray, log-distance, hata, cost231, satellite), environment (urban, dense urban, suburban, rural, indoor), pathLossExponent, txHeight, rxHeight (m), sensitivity, or noiseFigure + bandwidth + requiredSnr (or requiredEbN0 + dataRate), loraSf, fadeMargin (default 10 dB), availability (adds ITU-R rain), latitude, longitude, rainRate, polarization, elevation, orbit (GEO, MEO, LEO or an altitude), direction (downlink or uplink), gOverT, antennaTemperature, title.

## `fadeMargin` (type: `string`):

The margin a link must keep to count as closing, for links that don't give one, such as 10 dB. Empty: 10 dB.

## `model` (type: `string`):

For links that don't name one. Empty: free space, or Hata when an environment is named in its band.

## `noiseFigure` (type: `string`):

Receiver noise figure for links that don't give one, such as 6 dB. Empty: 6 dB.

## `charts` (type: `boolean`):

The budget as a waterfall and the received power by distance for each link.

## Actor input object example

```json
{
  "links": [
    "LoRa SF12 at 868 MHz, 14 dBm, 2 dBi antennas, 15 km, rural, gateway height 30 m, node height 2 m",
    "5.8 GHz point-to-point, 10 km, 23 dBm, 30 dBi dishes both ends, 1 dB cable loss each end, sensitivity -80 dBm, tower height 25 m, 99.99% availability at 40.4, -3.7",
    "12 GHz GEO downlink, EIRP 52 dBW, 0.6 m dish, elevation 30°, at 51.5, -0.1, 99.9%, 27 MHz bandwidth, noise figure 1 dB, Eb/N0 6 dB at 40 Mbps",
    "900 MHz, 30 W, base station 50 m, mobile 1.5 m, 8 km, urban, 15 dBi tx antenna, 0 dBi rx antenna, sensitivity -104 dBm",
    {
      "title": "Office Wi-Fi",
      "frequency": "2.4 GHz",
      "distance": "30 m",
      "txPower": "20 dBm",
      "antennaGain": 3,
      "model": "log-distance",
      "pathLossExponent": 3,
      "otherLosses": "6 dB",
      "sensitivity": "-82 dBm"
    }
  ],
  "charts": true
}
```

# Actor output Schema

## `results` (type: `string`):

One row per link: the summary and chart.

## `output` (type: `string`):

The OUTPUT record: every result in one JSON object.

## `files` (type: `string`):

Charts (PNG and SVG) and Markdown reports in the run's key-value store.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "links": [
        "LoRa SF12 at 868 MHz, 14 dBm, 2 dBi antennas, 15 km, rural, gateway height 30 m, node height 2 m",
        "5.8 GHz point-to-point, 10 km, 23 dBm, 30 dBi dishes both ends, 1 dB cable loss each end, sensitivity -80 dBm, tower height 25 m, 99.99% availability at 40.4, -3.7",
        "12 GHz GEO downlink, EIRP 52 dBW, 0.6 m dish, elevation 30°, at 51.5, -0.1, 99.9%, 27 MHz bandwidth, noise figure 1 dB, Eb/N0 6 dB at 40 Mbps",
        "900 MHz, 30 W, base station 50 m, mobile 1.5 m, 8 km, urban, 15 dBi tx antenna, 0 dBi rx antenna, sensitivity -104 dBm",
        {
            "title": "Office Wi-Fi",
            "frequency": "2.4 GHz",
            "distance": "30 m",
            "txPower": "20 dBm",
            "antennaGain": 3,
            "model": "log-distance",
            "pathLossExponent": 3,
            "otherLosses": "6 dB",
            "sensitivity": "-82 dBm"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("jumblemog/rf-link-budget-calculator").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "links": [
        "LoRa SF12 at 868 MHz, 14 dBm, 2 dBi antennas, 15 km, rural, gateway height 30 m, node height 2 m",
        "5.8 GHz point-to-point, 10 km, 23 dBm, 30 dBi dishes both ends, 1 dB cable loss each end, sensitivity -80 dBm, tower height 25 m, 99.99% availability at 40.4, -3.7",
        "12 GHz GEO downlink, EIRP 52 dBW, 0.6 m dish, elevation 30°, at 51.5, -0.1, 99.9%, 27 MHz bandwidth, noise figure 1 dB, Eb/N0 6 dB at 40 Mbps",
        "900 MHz, 30 W, base station 50 m, mobile 1.5 m, 8 km, urban, 15 dBi tx antenna, 0 dBi rx antenna, sensitivity -104 dBm",
        {
            "title": "Office Wi-Fi",
            "frequency": "2.4 GHz",
            "distance": "30 m",
            "txPower": "20 dBm",
            "antennaGain": 3,
            "model": "log-distance",
            "pathLossExponent": 3,
            "otherLosses": "6 dB",
            "sensitivity": "-82 dBm",
        },
    ] }

# Run the Actor and wait for it to finish
run = client.actor("jumblemog/rf-link-budget-calculator").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "links": [
    "LoRa SF12 at 868 MHz, 14 dBm, 2 dBi antennas, 15 km, rural, gateway height 30 m, node height 2 m",
    "5.8 GHz point-to-point, 10 km, 23 dBm, 30 dBi dishes both ends, 1 dB cable loss each end, sensitivity -80 dBm, tower height 25 m, 99.99% availability at 40.4, -3.7",
    "12 GHz GEO downlink, EIRP 52 dBW, 0.6 m dish, elevation 30°, at 51.5, -0.1, 99.9%, 27 MHz bandwidth, noise figure 1 dB, Eb/N0 6 dB at 40 Mbps",
    "900 MHz, 30 W, base station 50 m, mobile 1.5 m, 8 km, urban, 15 dBi tx antenna, 0 dBi rx antenna, sensitivity -104 dBm",
    {
      "title": "Office Wi-Fi",
      "frequency": "2.4 GHz",
      "distance": "30 m",
      "txPower": "20 dBm",
      "antennaGain": 3,
      "model": "log-distance",
      "pathLossExponent": 3,
      "otherLosses": "6 dB",
      "sensitivity": "-82 dBm"
    }
  ]
}' |
apify call jumblemog/rf-link-budget-calculator --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,jumblemog/rf-link-budget-calculator"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/yDCJj3LsNEAaL9RFO/builds/68hYgY9gSdx4BgSR1/openapi.json
