# Tidewatch relay — install guide

Tidewatch gets each site's data one of two ways, chosen per site on its **REST sources** page (admins):

- **On-site relay** (this guide): a relay on a server at the property polls everything locally and reports out over HTTPS. Use it when the property network is private. It runs on the **Windows 11 Pro management server** (PowerShell, nothing to install) or on any **Debian/Ubuntu server** ([Linux relay](#linux-relay-deb)).
- **[Local monitoring](#local-monitoring)**: the Tidewatch server pings the devices and calls the systems itself. Nothing to install at the property, but Tidewatch must be able to reach it (routed or over a VPN).

The Windows relay is a PowerShell script that runs on each property's on-site **Windows 11 Pro management server** (one relay per site). It uses only what ships with Windows: no Node, no Python, no agent installer.

Every 60 seconds it:

1. Calls each local vendor API (SonicWall, Corning SDLC, Corning AC Wireless Controller, 3CX, OpenEye) and records whether it answered, its HTTP status, response time and item count. It can also forward the JSON response.
2. Pings the ISP circuits. Every 5 minutes it also pings every device in `probes.csv`, and records **packet loss, latency and jitter**.
3. Reads this server's health: CPU, memory, disks, uptime, pending Windows Update reboot, and the Windows services you list.
4. Sends one report to `https://<your-site>/api/relay/ingest` over HTTPS with a bearer token.

The relay only makes **outbound** connections, so no inbound ports or port forwards are needed. If Tidewatch can't be reached, the relay holds up to an hour of reports and sends them once the connection is back.

## Quick install: Tidewatch Setup (recommended)

No PowerShell commands, no config files. On the property's Windows management server:

1. In Tidewatch, open the property, then choose **Connect a server → Get setup code** (on Overview, REST sources or Settings; admins only).
2. Click **TidewatchSetup.cmd** to download it (open Tidewatch on the server itself, or copy the file over), then double-click it. Choose **Yes** when Windows asks for administrator rights. If Windows shows "Windows protected your PC", choose **More info → Run anyway**.
3. The setup window opens with the code filled in. It then asks, one screen at a time, for:
   - the **address and login of each system** the site uses (SonicWall, SDLC, the AC controller, 3CX, OpenEye and any custom sources), each with a **Test** button that says right away whether it connected, the login was rejected or nothing answered;
   - the **ISP gateway IP** of each internet line, and which **Windows services** to watch (vendor services are found and ticked for you).
4. Choose **Install**. Setup saves an encrypted config, installs the relay as a startup task, sends the first report and starts monitoring. Add devices on the site's **Devices** page.

How it works: the setup code is one-time and expires after 30 minutes. Setup trades it for the site's relay token over HTTPS, so nobody copies a token. This **replaces the site's previous token**, so a relay for the same site on a *different* server stops reporting. Passwords never leave the server; they're encrypted with Windows DPAPI. API paths come from Tidewatch (the built-in defaults, custom source templates and the site's **API paths**), so nobody types URLs.

Run Tidewatch Setup again any time (from the console, or `%TEMP%\TidewatchSetup\TidewatchSetup.ps1`) to change an address or password. Choose "Keep that connection" to skip the code. Saved passwords are kept when left blank, and anything added to config.json by hand (extra endpoints, metrics, other sources) is preserved.

The rest of this guide covers the manual install, for IT staff who prefer to edit the files themselves.

## Files

| File | Purpose |
| --- | --- |
| `TidewatchSetup.ps1` | The setup window (downloaded by `TidewatchSetup.cmd` from `/api/relay/installer`) |
| `TidewatchRelay.ps1` | The relay itself |
| `Install-TidewatchRelay.ps1` | Installs it as a startup scheduled task running as SYSTEM, or removes it |
| `config.example.json` | Template for `%ProgramData%\TidewatchRelay\config.json` |
| `probes.example.csv` | Template for the ping list (`id,kind,name,host`). Devices can also be added in Tidewatch |

## Manual install

1. **Add the site in Tidewatch** (All sites → Add site, admins only). Tidewatch shows the site's **relay token once**, together with the install command. If the site already exists, issue a token on its Settings page.
2. **Download** the four files into one folder on the server, for example `C:\Temp\tidewatch-relay`:
   `https://<your-site>/relay/TidewatchRelay.ps1`, `Install-TidewatchRelay.ps1`, `config.example.json`, `probes.example.csv`.
3. **Open PowerShell as Administrator** in that folder and run the command Tidewatch showed you:
   ```powershell
   powershell -ExecutionPolicy Bypass -File .\Install-TidewatchRelay.ps1 -TidewatchUrl https://<your-site> -SiteId <site-id> -RelayToken <token>
   ```
   The token decides which site the reports belong to. No server settings or redeploys are needed per site.
4. **Create read-only API accounts** on each system. Use a dedicated account for the relay, not a person's login.
   - **SonicWall:** enable the SonicOS API (Device → Settings → Administration → SonicOS API) with **HTTP Basic authentication**. Create a dedicated local user for monitoring (for example `tidewatch-api`) in a **read-only admin** group. Don't use `admin`. SonicOS limits concurrent admin sessions, and the relay never forces other sessions off. It logs in with `POST /api/sonicos/auth`, makes its GET calls and logs out with `DELETE /api/sonicos/auth` on every poll. If a session expires during a poll (HTTP 401), the relay logs in once more and retries. If the firewall has no login endpoint (HTTP 404 or 405), it sends Basic auth on each call instead.
     - If the management interface uses a custom HTTPS port, include it in the address, for example `10.12.99.1:4441`.
     - Check the account from the server first. `curl.exe` prompts for the password, so it isn't saved in your command history: `curl.exe -k -i -u tidewatch-api https://10.12.99.1:4441/api/sonicos/reporting/interfaces/ipv4/status`. You should get HTTP 200 and a list of interfaces. `-k` is only for this manual check; the relay checks the certificate (see "Certificates" below).
   - **3CX:** create an API client (Admin → Integrations → API) and use its Client ID and secret (OAuth client credentials).
   - **Corning SDLC, Corning AC Wireless Controller, OpenEye:** ask the vendor or check the product's API documentation for the REST base path and auth method, then create a service account.
5. **Edit the config** (Notepad, run as Administrator): `%ProgramData%\TidewatchRelay\config.json`
   - Fill in each source's `url` and credentials. Set `"enabled": false` on any source that isn't ready yet.
   - Keep `trustSelfSigned: true` only for appliances that use self-signed certificates. It applies only to the host in that source's URL.
   - Add the Windows service names to `services`. Find them with `Get-Service | Sort DisplayName`.
6. **Edit the ping list**: `%ProgramData%\TidewatchRelay\probes.csv` (columns `id,kind,type,name,host,location`)
   - `circuit` rows should point at each ISP's **gateway / next-hop IP** on the SonicWall X1 and X2 interfaces. The firewall reaches a directly connected gateway through that same interface, so each circuit is measured on its own. Use the circuit ids from the site's Settings page in Tidewatch (`isp-primary` and `isp-backup` by default) so the carrier and capacity set there are matched up.
   - Add one `device` row per switch, AP, phone, recorder or camera you want loss and uptime for. You can export IPs from SDLC, the controller, 3CX and OpenEye.
   - `type` groups devices in the console. Use one of: `firewall`, `agg-switch`, `sdlc` (Corning SDLC / vNetC controller), `wireless-controller` (Corning AC Wireless Controller), `switch`, `access-point`, `pbx`, `phone`, `nvr`, `camera`, `server`, or the id of a class added in Tidewatch with **+ Add class** in the device form (it starts with `x-`, e.g. `x-badge-reader`). Anything else shows as "Other".
   - Keep each `id` stable. Uptime and downtime history are tracked per id.
7. **Encrypt the secrets** with Windows DPAPI. After this step they can only be decrypted on this machine:
   ```powershell
   powershell -ExecutionPolicy Bypass -File "C:\Program Files\Tidewatch Relay\TidewatchRelay.ps1" -ProtectConfig
   ```
   Run this again whenever you add or change a password.
8. **Test one cycle** without sending anything:
   ```powershell
   powershell -ExecutionPolicy Bypass -File "C:\Program Files\Tidewatch Relay\TidewatchRelay.ps1" -Once -DryRun
   ```
9. **Start it:** `Start-ScheduledTask -TaskName 'Tidewatch Relay'`. It also starts on every boot. Within a minute the REST sources page in Tidewatch shows the relay as connected.

## Linux relay (.deb)

The Linux relay does the same job as the Windows one, with the same `config.json` format, `probes.csv`, pause, Refresh now and API paths. It runs as the `tidewatch-relay` systemd service under its own user.

1. **Requirements:** Debian 12 or Ubuntu 24.04 (or newer), which ship Node.js 18+. On older releases, install Node.js 18+ from nodejs.org first. The server needs outbound HTTPS to Tidewatch and must be able to reach the property's systems and devices.
2. In Tidewatch, open the property, then **Connect a server → Linux (.deb) → Get setup code**. Tidewatch shows the three commands with your address and code filled in:
   ```sh
   curl -fLO https://<your-tidewatch>/relay/linux/tidewatch-relay_0.11.0_all.deb
   sudo apt install ./tidewatch-relay_0.11.0_all.deb
   sudo tidewatch-relay pair --url https://<your-tidewatch> --code K7QM-4ZTR
   ```
3. `pair` trades the code for the site's relay token, then asks for each system's address and login (passwords aren't echoed), tests each one and offers to pin self-signed certificates. It then asks for the ISP gateway IPs and any systemd services to watch, writes `/etc/tidewatch-relay/config.json` (mode 0640, readable only by root and the service) and starts the service. Pairing **replaces the site's previous token**, like Tidewatch Setup.

Operate:

- Logs: `journalctl -u tidewatch-relay -f`. Status: `systemctl status tidewatch-relay`.
- Test the sources: `sudo -u tidewatch-relay tidewatch-relay test` (or `test sonicwall`). One cycle without sending: `sudo -u tidewatch-relay tidewatch-relay once --dry-run`.
- Change an address or password: run `sudo tidewatch-relay pair` again with a new code (Enter keeps saved values), or edit `config.json` and `sudo systemctl restart tidewatch-relay`. Extra fields added by hand (metrics, extra endpoints, `probeCsv`) are kept.
- Pings use `fping` (installed as a recommended package) with the service's `CAP_NET_RAW`, then `ping`, then a TCP connect to ports 443/80/22 if ICMP isn't allowed.
- Host health covers CPU, memory, disks, uptime, `/var/run/reboot-required` and the systemd units in `services`.
- Secrets in `config.json` are plain text protected by file permissions (there's no DPAPI on Linux). Use read-only accounts.
- Remove: `sudo apt remove tidewatch-relay` (keeps the config), `sudo apt purge tidewatch-relay` (deletes it).
- Other distributions: download `/relay/linux/tidewatch-relay.mjs` and run it with Node.js 18+ (`node tidewatch-relay.mjs pair`). Set `TIDEWATCH_RELAY_CONFIG` to choose where the config lives.

## Local monitoring

With **Local monitoring** selected on a site's REST sources page, no relay is needed. Each minute the Tidewatch server pings each circuit gateway and calls each system's API. Every 5 minutes (or on Refresh now) it pings every device on the Devices page. Results show up exactly like a relay's.

- **Reachability:** the devices and systems must be reachable from the Tidewatch server (a routed network or a site-to-site VPN). Private IPs that only exist inside the property won't answer.
- **Logins:** on the REST sources page, **Connect** each system: address, read-only login, **Test**, and **Pin this certificate** for appliances with a self-signed certificate. Logins are encrypted (AES-256-GCM) with the `TIDEWATCH_SECRET_KEY` environment variable (32+ characters, e.g. `openssl rand -base64 32`) and are never shown again. Set it in Coolify before saving logins. Changing it later means entering the logins again.
- **Circuits:** enter each circuit's gateway IP under **ISP circuits** on the same page. Circuit usage paths (Mbps) can be set on the system that reports them (e.g. SonicWall `interfaces[name=X1].rx_bytes`, byte counters).
- **Ping:** the Docker image includes fping and ping. If ICMP isn't allowed where Tidewatch runs, it falls back to TCP connects (ports 443/80/22), and the page says so. `PING_METHOD=fping|ping|tcp` forces a method.
- **Switching:** a site uses one mode at a time. In local mode, the site's relay idles (0.9.0+ checks back every 10 minutes; reports from older relays are dropped). Switching closes the other mode's open outages, and history is kept. **Pause monitoring** works for both modes.
- **Several Tidewatch instances:** only one runs the checks (a Postgres advisory lock); another takes over if it stops. `LOCAL_MONITOR=off` keeps an instance out of it.

## Devices added in Tidewatch (relay 0.4.0+)

Admins can add, edit and remove devices on a site's **Devices** page instead of editing `probes.csv`. Each cycle the relay downloads that list from `https://<your-site>/api/relay/config` (same bearer token) and merges it with `probes.csv`:

- A device added in Tidewatch wins over a CSV row with the same `id`.
- Devices removed in Tidewatch are skipped, even if `probes.csv` still lists them. Restore them on the site's Settings page.
- The last downloaded list is cached in `%ProgramData%\TidewatchRelay\managed.json`, so the relay keeps pinging those devices if Tidewatch can't be reached when it starts.

A device can also have an **API path**: a GET the relay makes every 5 minutes (with the device pings). The path is either relative to the chosen REST source's host (it uses that source's login and session, so the source must be enabled in `config.json`), or a full `https://` URL, which is called without a login when no source is set. `{host}`, `{id}` and `{name}` are replaced with the device's values, for example `/api/v1/aps/{name}` or `https://{host}/status.json`. Tidewatch reads model, firmware, serial and a status text from the response with the paths set on the device.

**More calls and live values (relay 0.10.0+).** A device can list up to 6 more GETs by name (for example `clients` → `/api/v1/aps/{name}/clients`), made right after its API path with the same login. Each answer is reported under `calls` and shown, with the main one, in the device's **API output** (admins: tree, table or raw JSON; click a key to copy its path). **Live values** read a number or text from any of the calls on every pull (a path that points at a list counts its items) and show as tiles in the device's details; numbers also get a 24-hour chart. Older relays make only the main call.

## Pausing the relay (relay 0.9.0+)

**Pause relay** on a site's Overview (admins) stops the relay while the property is still being set up, so it doesn't send reports nobody needs yet. While paused, the relay doesn't ping, call vendor APIs or send reports. It only checks with Tidewatch every 10 minutes to see whether it has been resumed. **Resume relay** starts it again on that next check, beginning with a full round of device pings. Statuses in Tidewatch stay as they were when it was paused, and "Relay not reporting" isn't raised.

Older relays don't know about pausing: they keep pinging and sending every minute, and Tidewatch throws the reports away without storing them. Update the relay to stop those calls too.

## Pre-provisioned devices and Refresh now (relay 0.8.0+)

- **Import spreadsheet** on the Devices page adds many devices at once (hostname, IP address, MAC address, optional location and class). They show in Tidewatch straight away as *Awaiting first ping* and raise no alerts until the relay has pinged them. Every device, access points included, is pinged by ICMP every `deviceProbeIntervalSeconds` (300 = 5 minutes, the default), so the Windows server must be able to ping the AP management VLAN.
- **Refresh now** (Overview and Devices) and **Refresh** on selected devices ask the relay for a fresh pull. The request comes down with the device list (`refresh.requestedAt` / `refresh.targets`), and on its next cycle (within about a minute) the relay pings every device, or just the selected ones, and calls their API paths instead of waiting for the 5-minute round. Older relays ignore it.
- Devices moved to another site in Tidewatch disappear from this relay's list on its next download and appear in the other site's.

## API paths edited in Tidewatch (relay 0.5.0+)

Admins can change a REST source's API paths for one site on the **REST sources** page (**API paths** on each card): the health check path and the extra endpoints. Custom sources also send the paths from their template. The relay downloads them with the device list and applies them before each cycle:

- A health path replaces the path (and query) of the source's `url`. An extra endpoint path replaces the endpoint of the same name, or adds it.
- Paths always start with `/`. The scheme, host, port and login still come from `config.json`, so Tidewatch can change what is called but never where credentials are sent.
- Nothing is written back to `config.json`. **Reset to defaults** in Tidewatch (or an older relay) goes back to the paths in the file.

## Custom REST sources

Any REST API can be added on the **REST sources** page with **Add REST source**. The template asks for the base URL (with a placeholder host), auth type, health check path, extra endpoints and where device records sit in the JSON. Tidewatch then shows the `config.json` block for the relay. Paste it into `sources`, replace the host placeholder and the `CHANGE-ME` values, and run `-ProtectConfig`. Credentials stay on the server.

## Usage metrics (ISP circuit Mbps)

Any source can pull numbers out of its API response with a `metrics` list. Tidewatch uses `download_mbps` and `upload_mbps` for the circuit whose id matches `target`:

```json
"metrics": [
  { "target": "isp-primary", "metric": "download_mbps", "path": "interfaces[name=X1].rx_bytes", "mode": "counter", "scale": 0.000008 }
]
```

- `path` walks the JSON: `a.b`, `list[0]`, and `list[name=X1]` (first item whose `name` is `X1`).
- `mode: "counter"` turns a cumulative counter into a per-second rate between polls. `scale: 0.000008` converts bytes/s to Mbps. Use `mode: "gauge"` (the default) when the API already reports a rate.
- To find the right path, set `"forwardBody": true` and run `-Once -DryRun`. The printed `payload` shows exactly what SonicOS returned. Bad paths are logged as warnings, and the rest of the report still goes out.

## Inventory, firmware and WLANs

With `"forwardBody": true`, the relay forwards each source's JSON response and Tidewatch reads device model, firmware, serial number and WLANs from it. Most APIs keep these on a different endpoint than the health check, so a source can list `extraEndpoints`. These are extra GET calls made with the same login, and each response is forwarded under its name:

```json
"extraEndpoints": {
  "version": "https://<firewall>/api/sonicos/version"
}
```

- Tidewatch finds device lists by itself (arrays of records with a name plus a model, firmware, serial, MAC or IP). It recognizes common key names such as `model`, `firmwareVersion`, `serial_number` and `ipAddress`. It finds WLANs as records with an `ssid`.
- Each record is matched to a `device` row in `probes.csv`, by IP (the `host` column) first and then by name or id. Matched devices show their model and firmware in the console. Each REST source card shows how many records were found and how many were matched. If the matched count is low, check that the names or IPs in `probes.csv` match what the vendor's software uses.
- When a vendor uses unusual key names, set exact paths in `connectorMaps` in `src/data/site.ts` (for example `fields: { firmware: 'sw.ver' }`). Paths use the same syntax as metrics.
- Expected firmware goes in `firmwareBaselines` in the same file, keyed by device class or by class and model. Devices on an older version are flagged on the Overview and Devices screens and raise an alert.
- Failing extra endpoints are logged as warnings. They don't mark the source as down.

## Corning SDLC switches and ports (relay 0.11.0+)

SDLC (vNetC) answers `GET /api/request?query=<name>` with Basic auth (use a read-only SDLC user). The SDLC block calls `query=status` (every switch's state, power supplies, fans, temperatures), `query=networks` (each device's `dev_id`, model, serial, last boot) and then, per switch, `query=device_details&dev_id=<id>` for its ports. That last one is an `itemCalls` entry: one GET per record of an earlier response, reported under its name as `{ "<id>": { "name": …, "body": … } }` and trimmed so reports stay small:

```json
"itemCalls": {
  "details": {
    "from": "networks", "idField": "dev_id", "where": { "product_class": ["Switch", "FTTP"] }, "labelField": "endpoint_name",
    "url": "https://<vnetc>/api/request?query=device_details&dev_id={id}",
    "keep": {
      "ports": { "path": "[0].ports", "keys": "^(swp\\d+|PON|Eth\\d+)$",
                 "fields": ["port_status", "link-speed", "link-duplex", "poe_status", "sfp_type", "sfp_vendor_name", "sfp_vendor_part_number",
                            "rx_optical_level", "tx_optical_level", "last_link_change"] },
      "macs": { "path": "[0].mac_addresses", "keys": "^(swp\\d+|cpe-Eth\\d+)$", "fields": ["mac", "org"], "skip": { "fabric": true }, "max": 48 }
    }
  }
}
```

A `where` value can be a list (switches and ONTs here: an ONT's `PON` port carries its optics, its `Eth` ports what's plugged in). Each `keep` entry keeps one part of the response: the object at `path`, its keys matching `keys`, and `fields` of each record; lists drop records matching `skip` and, with `max`, keep at most that many items plus a `total`. Every switch appears under Devices on its own (no `probes.csv` row needed), with its ports: active ports with type (optical/copper), speed, PoE, fiber light levels and what's connected (Tidewatch devices matched by MAC, the switch on the other end of a fabric link, or unknown MACs by vendor), and ports that lost link in the last 7 days (which raise an alert). Ports down since the switch booted, or for longer than 7 days, count as unused. Tidewatch Setup, `tidewatch-relay pair` and local monitoring write this block for you. Relays older than 0.11.0 skip `itemCalls` (no port details).

## Firewall interfaces

The SonicWall source's main URL (`/api/sonicos/reporting/interfaces/ipv4/status`) lists every port. Tidewatch reads each port's name, zone, type, enabled flag, link state (`connected` / `status`) and speed, and shows them on the site's **ISP circuits** page. Each circuit's handoff (for example `SonicWall X1`, set on the Settings page) is matched to its port. If the firewall reports no link on that port, the circuit is marked down right away, without waiting for pings to fail. IP addresses and subnet masks are never shown.

**Circuit usage.** The `failover` extra endpoint (`/api/sonicos/reporting/failover-lb/statistics`) lists each WAN member of the load-balancing groups (`member_name`, e.g. `X26`) with cumulative `rx_bytes` and `tx_bytes`. Tidewatch turns the change between two pulls into Mbps for the circuit whose handoff is that port: received = download, sent = upload (IPv4 and IPv6 groups are added together). Usage paths set by hand in a Local monitoring connection still win for their circuit. Set each circuit's handoff to its WAN port on the Settings page.

## Certificates

The relay checks every HTTPS certificate:

- **Normal validation:** certificates that Windows trusts are accepted.
- **Pinned certificate (`certThumbprint`):** appliances reached by IP usually have a self-signed certificate. Pin its SHA-256 fingerprint, and the relay accepts that exact certificate and nothing else. In Tidewatch Setup, press **Test**. Setup shows the fingerprint and pins it. Compare it with the certificate on the device (SonicWall: Device → Settings → Certificates). If the certificate is later renewed, Test reports that it changed. Press Test again to accept the new one. To pin by hand, add `"certThumbprint": "AB:CD:…"` to the source in config.json (colons and spaces are optional).
- **`trustSelfSigned: true` without a pin** accepts any certificate from that host. This is only meant for the first Test. The relay logs a warning until the source is pinned.

## Timeouts, errors and logging

- Each API call times out after 20 seconds (`timeoutSeconds` on a source). Each source gets 45 seconds in total for login, the main call, extra endpoints and device paths (`budgetSeconds`). Anything left over is skipped and logged, so one slow system can't hold up the report.
- **POST login (relay 0.10.0+).** For APIs that log in by POSTing a username and password, a source's `auth` can be `"type": "login"`: `loginUrl`, `loginContentType` (`json` or `form`), `loginBody` with `{username}` and `{password}` placeholders (escaped for the format), and `tokenFrom`: `cookie` (the session cookie is kept), `body` (`tokenField` is the token's JSON path, e.g. `data.token`) or `header` (`tokenField` is the response header). A token is sent on each GET in `tokenHeader` (default `Authorization`) after `tokenPrefix` (e.g. `Bearer `). Optional `logoutUrl` + `logoutMethod`. Pick **Login with POST** in a REST source template and the config.json block is generated for you; Tidewatch Setup, `tidewatch-relay pair` and local monitoring ask for the username and password as usual.
- A login failure is reported as `Login failed (HTTP 401)`, separate from a failing data path. In Setup, Test explains rejected logins, missing paths, busy or out-of-session firewalls (HTTP 429/503), timeouts and certificate problems.
- Passwords and other secrets are encrypted in config.json (DPAPI). The relay never logs passwords or `Authorization` headers. Every log line and every error sent to Tidewatch is scrubbed of anything that looks like a credential.

## Rotating a token

On the site's Settings page, choose **Issue new token**. The old token stops working immediately. On the server, run `Install-TidewatchRelay.ps1 -RelayToken <new token>` (or paste it into `tidewatch.token` and run `-ProtectConfig`). The relay picks it up on its next cycle.

Chicago's relay was installed before per-site tokens. It keeps working with the `RELAY_TOKEN` environment variable until a token is issued on its Settings page, after which that variable is no longer used.

## Operate

- Logs: `%ProgramData%\TidewatchRelay\logs\relay.log`. The log rotates at 5 MB.
- Config changes are picked up on the next cycle. There's no need to restart.
- To update: copy the new `TidewatchRelay.ps1` over the old one, then run `Stop-ScheduledTask` followed by `Start-ScheduledTask`.
- To remove: `.\Install-TidewatchRelay.ps1 -Uninstall`. Add `-Purge` to also delete the config and logs.
- Firewall egress: the server needs outbound HTTPS (443) to your Tidewatch domain.

## Notes

- The vendor endpoint paths in `config.example.json` are starting points. Confirm each one against your version's API docs. Tidewatch stores each source's latest JSON response (and its extra endpoints), which is where inventory, firmware and WLANs come from.
- The relay sends each probe's `host` so inventory can be matched by IP. Tidewatch stores it but never sends it to the browser.
- The console currently shows only a public-safe summary of relay data (status, counts, averages). It does not show IPs, errors or raw payloads. Staff sign-in comes before anything more detailed is displayed.
