> ## Documentation Index
> Fetch the complete documentation index at: https://playbook.smedleygroup.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Local Development

> Working on Telemetry without a track: standing in for the kart fleet with the simulator, and reproducing a conversion on your own machine.

Neither half of Telemetry needs the real thing to work on. The charging side can be driven by a simulator that stands in for the kart fleet, and the DAQ side can be converted locally from a zip. This page covers both.

## Simulating The Kart Fleet

None of this needs a kart, an ECAN or a track network to work on. `KartSimulatorV2` stands in for the hardware: it accepts the receiver's TCP connection, answers request frames using the same DBC the pipeline decodes with, and broadcasts controller frames on its own.

```
KartSimulatorV2.exe <batterySpec> <ports> <fittedNodes> <dataLoggerAttached>
```

| Argument | Default | Meaning |
| - | - | - |
| `batterySpec` | Required | Which spec to simulate, and so which DBC and request set. The same strings `ip-config.json` uses |
| `ports` | `1234` | Comma separated, so one process can present more than one port. Some specs accept only a single port per process |
| `fittedNodes` | `3` | How many battery nodes answer |
| `dataLoggerAttached` | `false` | When true, the simulator behaves as though a logger or DAQ is doing the polling |

`simulate.bat` alongside it starts a whole fleet, one process per kart on consecutive ports from 1234. Point `ip-config.json` at the host with matching ports and the receiver cannot tell the difference. See [The Configuration To Point It At](#the-configuration-to-point-it-at) for a working one.

> [!NOTE]
>
> `fittedNodes` is the most useful switch here, because it reproduces the [request fan out](/software/developer/estate/systems/telemetry/receiver#more-requests-than-there-are-nodes) on your own machine. Set it below the five nodes the request set covers and you can watch unanswered requests behave correctly without needing a particular kart in front of you.

> [!NOTE]
>
> The controller side of the simulator broadcasts at 50 Hz, which is the figure the [request rate](/software/developer/estate/systems/telemetry/receiver#the-rate-and-why-it-is-low) is set against.

### The Configuration To Point It At

A simulated fleet still needs an `ip-config.json`, and the file is [excluded from source control](/software/developer/estate/systems/telemetry/track-operations#the-kart-fleet-configuration), so a fresh clone has nothing to start from. Two kart entries from a working one:

```json ip-config.json theme={null}
{
  "littleEndianTxData": {
    "data": {
      "mep": [ /* 55 request frames, five nodes across eleven groups */ ],
      "aentron": [ /* 8 request frames */ ]
    }
  },
  "karts": [
    {
      "kartId": "EK3234",
      "batterySpec": "mep",
      "category": "JNR",
      "type": "EK3",
      "connections": [
        {
          "ipAddress": "172.25.160.1",
          "port": 1234,
          "isDataLoggerAttached": false,
          "isLittleEndian": true,
          "txChunkSize": 5,
          "saveRawData": false,
          "fullRequestDatasetsPerSecond": 2
        }
      ]
    },
    {
      "kartId": "EK2445",
      "batterySpec": "aentron",
      "category": "CAD",
      "type": "C1.6",
      "connections": [
        { "ipAddress": "172.25.160.1", "port": 1244, "isDataLoggerAttached": false, "isLittleEndian": true, "txChunkSize": 1, "saveRawData": false, "fullRequestDatasetsPerSecond": 2 },
        { "ipAddress": "172.25.160.1", "port": 1245, "isDataLoggerAttached": false, "isLittleEndian": true, "txChunkSize": 1, "saveRawData": false, "fullRequestDatasetsPerSecond": 2 }
      ]
    }
  ]
}
```

Those two are the whole shape of the file. A `mep` kart takes one connection and a `txChunkSize` of 5, while an `aentron` kart in `CAD` takes two connections and a `txChunkSize` of 1, one per battery node. Neither carries `isActive`, which is [optional and defaults to true](/software/developer/estate/systems/telemetry/track-operations#what-it-contains).

> [!NOTE]
>
> The complete file is the JSON at `images/software/developer/estate/systems/telemetry/ip-config.json` in the source of these docs. It is a real 20 kart configuration pointed at the simulator rather than a sanitised sample, so it runs as it stands against `simulate.bat`. Copy it out of the repository into the receiver's `config` folder.

#### The Address Is The Docker Gateway, Not Loopback

Every connection in it uses `172.25.160.1`, which looks like a track address and is not one. It is the **Windows Docker NAT gateway**, so it is how the receiver reaches the host from inside its own container.

> [!WARNING]
>
> `172.25.160.1` is not guaranteed to be your gateway. Docker assigns the NAT subnet when it creates the network, and it can differ between machines and change when the network is recreated. If nothing connects, confirm the address with `docker network inspect` and look at the gateway of the network the stack is on, then correct the file. `host.docker.internal` is the alternative where your Docker version resolves it.

#### How The Ports Line Up

`simulate.bat` hands out consecutive ports from 1234, and the file expects exactly that sequence. Ports are consumed per connection rather than per kart, so the multi connection karts take two each:

| Karts | Ports | Battery spec | Category | Connections each |
| - | - | - | - | - |
| `EK3234` to `EK3243` | 1234 to 1243 | `mep` | `JNR` | One |
| `EK2445` to `EK2523` | 1244 to 1253 | `aentron` | `CAD` | Two |
| `EK154` to `EK158` | 1254 to 1258 | `aentron` | `BB` | One |

> [!NOTE]
>
> Change how many karts the batch file starts and the ports shift for everything after it, because they are handed out in sequence rather than fixed per kart. Trim karts from the end of the file rather than the middle, or the ports and the processes stop agreeing.

## Running A Conversion Locally

Reproducing a conversion on your own machine is the fastest way to understand a failure, and it is how a stuck run gets fixed.

**1. Restore the databases**

Restore `TalentId_PROD` and `GklPlatform_PROD` using [db-setup.zip](https://robsmedley.sharepoint.com/sites/mainshare/_layouts/15/guestaccess.aspx?share=IQCe2v0u1NhSQouDE_zyFiRxAXRCP8JHimqlhCUcfH8CLTE\&e=8g3gD6).

**2. Run both APIs**

The conversion requires both the TalentID API and the GKL Platform API to be running, and restored to their latest versions. The telemetry API can also be run locally.

**3. Start the debugger**

In Visual Studio Code, use the `launch.json` file, which runs `run_stl_export.py`. Open the folder in VS Code, press `ctrl-shift-p`, then choose **Debug: Select and Start Debugging**.

**4. Point it at the right zip**

Edit the file with the correct zip, and choose whether the file should be forced, meaning always reconvert, and whether the output should also be written to the `LocalData` folder.

Remember to change the bucket in `launch.json` from dev to prod.

**5. Push the fix back**

Keep the database in local mode so it stays in sync. Once the issue is fixed, re-upload the zip to S3, with `force = true` in the metadata if necessary.

## Related Documentation

| Page | Relevance |
| - | - |
| [The Charging Data Receiver](/software/developer/estate/systems/telemetry/receiver) | What the simulator is standing in for |
| [Upload and Conversion](/software/developer/estate/systems/telemetry/daq-pipeline) | What a conversion does when it runs for real |
| [Troubleshooting](/software/developer/estate/systems/telemetry/troubleshooting) | The symptoms you would be reproducing |
| [Deployment and the Pipeline](/software/developer/estate/systems/telemetry/deployment) | Getting a fix from your machine to a track |


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.