Skip to content

Configuration Guide

This is the full list of every setting, for when you need to look one up.

Everything else on this page has a sensible default. These five are the ones worth knowing about:

Setting What it does
number_of_devices How many panels to track. Set it to your panel count (or a bit more).
power_calibration Nudges all power readings up or down if they don’t match your inverter. 1.05 = +5%.
history_interval How often history is saved to flash, in minutes. Default 30. Lower gives more detailed charts but wears the flash faster and stores fewer days.
reset_at_midnight Starts the daily energy and peak-power figures fresh each night.
inverters: Groups your strings under inverter names so the dashboard mirrors your real layout.
api_token / web_password Passwords for the dashboard and API. Worth setting.

The first three can be changed live in the web dashboard (Tools → Device Configuration) without rebuilding or reflashing anything — handy for tuning power_calibration against your inverter’s own display.

tigo_monitor:
id: tigo_hub
uart_id: tigo_uart
update_interval: 30s
number_of_devices: 20
cca_ip: "192.168.1.100"
sync_cca_on_startup: true
time_id: ha_time
reset_at_midnight: true
power_calibration: 1.0
night_mode_timeout: 60
inverters:
- name: "Inverter 1"
mppts: ["MPPT 1", "MPPT 2"]
Option Type Default Description
uart_id ID Required UART component ID
update_interval Time 60s Sensor publish interval
number_of_devices Integer 5 Max devices to track
cca_ip String None Tigo CCA IP address
sync_cca_on_startup Boolean true Auto-sync CCA on boot
time_id ID None Time component for midnight reset
reset_at_midnight Boolean false Reset daily totals at midnight
power_calibration Float 1.0 Power multiplier (0.5-2.0)
night_mode_timeout Integer 60 Minutes before night mode (1-1440)
stale_timeout Integer 10 Minutes without data before a device’s production values (power, current, efficiency, duty cycle) zero out. 0 disables. Voltage/temperature keep their last reading for diagnostics
history_interval Integer 30 Minutes between on-flash history snapshots (5–1440). Lower means finer charts but proportionally more flash wear and shorter retention — see Saving History to Flash. Values under 15 log a warning at build time
inverters List None Inverter grouping config

Group MPPTs by inverter for organized dashboard display:

inverters:
- name: "South Inverter"
mppts:
- "MPPT 1"
- "MPPT 2"
- name: "North Inverter"
mppts:
- "MPPT 3"
- "MPPT 4"

MPPT labels must match your CCA’s labels exactly. The dashboard then shows your array the way it’s really built: Inverter → MPPT → String → Panel.

You can rename inverters and strings directly in the dashboard — click the ✎ next to any label on the Topology page. The new name is saved on the device (in NVS, its small settings memory) and survives reboots, so you can switch to friendly names like “South Roof” without rebuilding your config.

The name in your YAML stays the real identity behind the scenes; the rename only changes what’s displayed. Clear it to go back to the original.

Click the rating pill on the Topology page to enter your panel’s rated watts — the number on the sticker, e.g. 400. Saved on the device. Once set:

  • Each panel shows what percentage of its rating it’s currently making.
  • Underperforming panels are judged against that rating rather than against their neighbours, which is more reliable. (At dawn, when the whole string is below 5% of rated, it’s marked as sleeping rather than as broken.)
  • Each string shows its total output as a percentage of what it could be making.

Leave it unset and panels are compared against each other instead.

Reset peak power and energy daily:

time:
- platform: homeassistant
id: ha_time
tigo_monitor:
id: tigo_hub
uart_id: tigo_uart
time_id: ha_time
reset_at_midnight: true

Adjust if readings differ from inverter:

tigo_monitor:
power_calibration: 1.05 # +5% to all power readings

Applied to: individual device power, string aggregates, total system power, energy calculations.

Tip: power_calibration (and night_mode_timeout, reset_at_midnight, sync_cca_on_startup, cca_ip) can also be edited live in the web UI under Tools → Device Configuration and stored on-device, so you can tune them without reflashing. See On-device configuration.


tigo_server:
tigo_monitor_id: tigo_hub
port: 80
api_token: "your-secret-token"
web_username: "admin"
web_password: "secure-password"
# Optional: read the CCA over Bluetooth (firmware 4.0.4+ locks local HTTP)
cca_source: ble # http (default) | ble | auto
ble_client_id: tigo_cca_ble
# Optional: recover the panel/string layout from Tigo's cloud
cloud_import: true
Option Type Default Description
tigo_monitor_id ID Required Reference to tigo_monitor
port Integer 80 HTTP port
api_token String None Bearer token for API auth
web_username String None HTTP Basic Auth username
web_password String None HTTP Basic Auth password
backlight ID None Light component to expose via the optional POST /api/backlight endpoint (units with a backlight wired)
cca_source Enum http CCA Info data source: http, ble, or auto. ble/auto require ble_client_id
ble_client_id ID None A ble_client: for the CCA’s BLE MAC. The MAC is a default/seed — reselect it via the CCA Connection search and store it on-device
cloud_import Boolean false Enable the Tigo Cloud page + cloud layout import (compiles the cloud client + TLS cert bundle)

In plain terms: newer Tigo CCAs refuse to answer questions over your home network. This option asks them over Bluetooth instead, so you can still pull your panel names and layout across. If your CCA is on older firmware you don’t need it.

Tigo CCA firmware 4.0.4+ (incl. 4.0.5-ct) locks the local HTTP API, so the CCA Info page can instead source data over Bluetooth. With cca_source: ble and a ble_client_id, tigo_server becomes the BLE client and talks the CCA’s mobile_api over GATT. The link is opened on demand and dropped after each read so the Tigo phone app can still connect (the CCA allows one BLE central at a time).

ble_client:
- mac_address: "04:C0:5B:AA:BB:CC" # default/seed — required by ble_client, overridable in the UI
id: tigo_cca_ble
auto_connect: false # we connect on demand; don't hold the link at boot
esp32_ble:
use_psram: true # BLE host buffers from PSRAM
max_connections: 1
esp32_ble_tracker:
scan_parameters:
interval: 320ms
window: 60ms
active: true

You don’t have to know the MAC up front: the CCA Info page’s CCA Connection card scans for the CCA by its Tigo 04:C0:5B address prefix and lets you pick it. The choice is saved on-device (NVS) and overrides the YAML MAC across reboots; Revert restores the YAML value. The ble_client: block (with some MAC) is still required — mac_address is a required field, so leave your real MAC there as the default.

On-device configuration (Tools → Device Configuration)

Section titled “On-device configuration (Tools → Device Configuration)”

These runtime knobs can be set in the web UI and persisted to the ESP32 (NVS) without reflashing — handy for tuning power_calibration against a reference meter, or changing behavior on a deployed unit:

Knob Notes
power_calibration Applied immediately (every power calc reads it live)
night_mode_timeout Minutes of silence before readings are zeroed
reset_at_midnight Reset peaks + daily energy at local midnight (needs a time source)
sync_cca_on_startup Query the CCA over local HTTP at boot (only with a cca_ip)
cca_ip CCA IP for local HTTP queries (older firmware)

The YAML value is the default. A stored value overrides it until you press Revert, which clears the override so future YAML edits apply again (Revert is enabled only when the live value differs from the default). Structural settings (inverter layout, device count, ports, IDs) and auth (api_token/web_*) stay YAML-only — the latter because NVS is plaintext-at-rest.

In plain terms: your installer already typed your panel names and layout into Tigo’s system. This pulls that work down so you don’t have to retype it. You sign in once with your normal Tigo account; only the resulting access token is kept on the device, never your password.

When the CCA’s local HTTP is locked, the panel names + string/MPPT/inverter layout can be recovered from Tigo’s cloud (the same API the mobile app uses). Enter your Tigo account in the Configure modal on the Tigo Cloud page — only the resulting bearer token is persisted to NVS, never the password. The page also shows Tigo’s own per-equipment health/status/history; layout import is a button on the Topology page. HTTPS is verified against the mbedTLS certificate bundle, which cloud_import enables automatically.

API Authentication (Bearer token):

Terminal window
curl -H "Authorization: Bearer your-token" http://esp32/api/devices

Web Authentication (HTTP Basic):

  • Browser prompts for username/password
  • Credentials cached per session

Health Check (/api/health) requires no authentication.


No address required. Each hub sensor is a separate platform entry — sensor type is auto-detected from the name keywords:

sensor:
- platform: tigo_monitor
tigo_monitor_id: tigo_hub
name: "Total System Power"
- platform: tigo_monitor
tigo_monitor_id: tigo_hub
name: "Total System Energy"
- platform: tigo_monitor
tigo_monitor_id: tigo_hub
name: "Active Device Count"
- platform: tigo_monitor
tigo_monitor_id: tigo_hub
name: "Missed Frame Count"
- platform: tigo_monitor
tigo_monitor_id: tigo_hub
name: "Invalid Checksum Count"
- platform: tigo_monitor
tigo_monitor_id: tigo_hub
name: "Free Internal RAM"
- platform: tigo_monitor
tigo_monitor_id: tigo_hub
name: "Min Free Internal RAM"
- platform: tigo_monitor
tigo_monitor_id: tigo_hub
name: "Free PSRAM"
- platform: tigo_monitor
tigo_monitor_id: tigo_hub
name: "Free Stack"

Sensor type is inferred from name keywords:

  • power, total, sum, watt, system, combined → Total power sensor
  • energy, kwh, kilowatt, wh → Energy sensor
  • count, devices, discovered, active, number → Device count sensor
  • frame, missed, lost, dropped → Missed frame counter
  • checksum, invalid, crc, error → Invalid checksum counter
  • internal, ram, heap (with min/minimum/watermark) → Min free internal RAM
  • internal, ram, heap (without min keywords) → Free internal RAM
  • psram → Free PSRAM sensor
  • stack → Free stack sensor

Keyword precedence: matching is order-sensitive. checksum/frame are matched before count, so a name like "Invalid Checksum Count" or "Missed Frame Count" resolves to the checksum/frame counter rather than the device-count sensor even though it contains the word “count”. Likewise psram is matched before the generic ram keyword.

Important: Each hub-level sensor must be its own - platform: tigo_monitor entry. Do not nest them as sub-keys (e.g., power_sum:) under a single platform entry — that format is only for per-device sensors.

Requires address from device discovery:

sensor:
- platform: tigo_monitor
tigo_monitor_id: tigo_hub
address: "1234"
name: "Panel 1"
power: {}
peak_power: {}
voltage_in: {}
voltage_out: {}
current_in: {}
temperature: {}
rssi: {}
duty_cycle: {}
efficiency: {}
power_factor: {}
load_factor: {}

address and name only say which panel and what to call it — the entities come from the sub-keys, so list at least one. An entry with none creates no entities, and is rejected at validation time rather than silently skipped.

ESPHome’s sub-devices feature lets one ESPHome node expose multiple logical “devices” to Home Assistant. The generator in the Tools view emits this for you — pick Per MPPT, Per inverter, or Per panel in the grouping selector and the YAML it produces will include an esphome.devices: block plus a device_id: on each child sensor.

If you’re hand-writing the YAML, the same pattern works: declare the device once on the panel’s base config and the schema propagates it to every child sensor (power_in, peak_power, voltage_in, etc.) — no need to repeat device_id: on each:

esphome:
name: tigo-monitor
devices:
- id: tigo_mppt_1
name: "MPPT 1"
- id: tigo_mppt_2
name: "MPPT 2"
sensor:
- platform: tigo_monitor
tigo_monitor_id: tigo_hub
address: "1234"
name: "Panel 1"
device_id: tigo_mppt_1 # propagates to all child sensors below
power: {}
voltage_in: {}
current_in: {}
temperature: {}
- platform: tigo_monitor
tigo_monitor_id: tigo_hub
address: "5678"
name: "Panel 2"
device_id: tigo_mppt_1
power: {}
voltage_in: {}
current_in: {}
temperature: {}

After flashing, Home Assistant shows “MPPT 1” and “MPPT 2” as separate device cards, each grouping the entities for its panels.

A panel’s barcode, firmware version and device info are text entities, but they are declared like every other measurement — as sub-keys of a sensor: entry. There is no text_sensor: platform for tigo_monitor; the component creates the text entities itself.

sensor:
- platform: tigo_monitor
tigo_monitor_id: tigo_hub
address: "1234"
name: "Panel 1"
barcode: {}
firmware_version: {}
device_info: {}

They mix freely with the numeric sub-keys, so one entry per panel covers both:

sensor:
- platform: tigo_monitor
tigo_monitor_id: tigo_hub
address: "1234"
name: "Panel 1"
power: {}
temperature: {}
barcode: {}
binary_sensor:
- platform: tigo_monitor
tigo_monitor_id: tigo_hub
night_mode:
name: "Solar Night Mode"

button:
- platform: tigo_monitor
tigo_monitor_id: tigo_hub
name: "Generate YAML Config"
button_type: yaml_generator
- platform: tigo_monitor
tigo_monitor_id: tigo_hub
name: "Print Device Mappings"
button_type: device_mappings
- platform: tigo_monitor
tigo_monitor_id: tigo_hub
name: "Sync from CCA"
button_type: sync_from_cca
- platform: tigo_monitor
tigo_monitor_id: tigo_hub
name: "Reset Node Table"
button_type: reset_node_table

Metric Formula Range Description
Efficiency (Power Out / Power In) × 100% 90-98% DC-DC conversion
Power Factor Voltage Out / Voltage In 0.8-1.2 Voltage regulation
Duty Cycle (Raw / 255) × 100% 0-100% PWM duty cycle
Load Factor (Duty / 100) × (Power / 1000) Variable Composite metric

Required configuration:

esp32:
board: esp32dev
framework:
type: esp-idf
version: recommended
sdkconfig_options:
CONFIG_UART_ISR_IN_IRAM: "y" # Reduces packet loss

Required. Every install needs this:

esphome:
platformio_options:
board_build.flash_mode: dio
psram:
mode: octal
speed: 80MHz
esp32:
board: m5stack-atoms3
variant: esp32s3
framework:
type: esp-idf
sdkconfig_options:
CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240: "y"
CONFIG_ESP32S3_DATA_CACHE_64KB: "y"
CONFIG_ESP32S3_DATA_CACHE_LINE_64B: "y"
CONFIG_SPIRAM_MODE_OCT: "y"
CONFIG_SPIRAM_SPEED_80M: "y"

Re-flashing to enable PSRAM: if you previously flashed without PSRAM, clean the ESPHome build files and erase the ESP32 flash completely (esptool.py erase_flash) before re-flashing. ESPHome doesn’t rebuild the bootloader automatically when PSRAM settings change.

PSRAM holds the bulk device data, but a few things still come out of the small internal (DMA-capable) heap and grow with install size. On a big array (30+ devices) they can exhaust it — the tell-tale symptom is new TCP connections resetting after a few minutes of uptime (OTA fails with Connection reset by peer, esphome logs won’t attach) while the existing Home Assistant connection keeps working and a reboot temporarily clears it.

Check the low-water mark at any time — heap_min_free in curl http://<device-ip>/api/health. If it drops into the low single-digit KB, tune these:

  • WiFi/lwIP buffers. Move them into PSRAM to free internal RAM:

    esp32:
    framework:
    type: esp-idf
    sdkconfig_options:
    CONFIG_SPIRAM_TRY_ALLOCATE_WIFI_LWIP: "y"
  • Entity count. Every per-panel sensor declared in YAML costs ~110–150 bytes of internal RAM at boot (the sensor object plus API registration). It scales: 64 panels × 7 sensor types ≈ 450 entities ≈ 50–70 KB — the largest static consumer on a big install. Declare only the per-panel sensors you actually use in Home Assistant; the web dashboard shows every metric for every panel regardless, at no per-entity cost. For HA aggregates, prefer the string_label: per-string power sensor (one entity per string) over declaring — or lambda-summing — per-panel sensors.

  • UART RX buffer. CONFIG_UART_RX_BUFFER_SIZE (and the matching rx_buffer_size: on the uart: component) allocate from internal RAM, never PSRAM. 2–8 KB is plenty on an ESP32-S3 at 38400 baud; a 32 KB buffer silently spends a sixth of the usable internal heap. See UART Optimization.


Persistent time-series history is opt-in via two extra dependencies and a custom partition table. See Saving history to flash for the full schema, sizing, and query reference.

Quick form (8 MB AtomS3R):

esp32:
framework:
type: esp-idf
components:
# A fork, pinned by exact commit — the registry build makes each
# snapshot take 21 s instead of under 1 s. See "Saving history to
# flash" for why, and copy the pin from there if this looks stale.
- name: zakery292/esp_tsdb
source: https://github.com/RAR/esp_tsdb.git
ref: ebfc360f00263ab90116ee3e556a9153ab4041a2
- joltwallet/littlefs^1.16
sdkconfig_options:
CONFIG_PARTITION_TABLE_CUSTOM: "y"
CONFIG_PARTITION_TABLE_FILENAME: "boards/partitions/tigo-8mb.csv"

Without these, the rest of the component still works — you just lose the History view and the /api/history/* and /api/tsdb/stats endpoints.


Add ESPHome filters to any sensor:

sensor:
- platform: tigo_monitor
tigo_monitor_id: tigo_hub
name: "Total System Power"
filters:
- sliding_window_moving_average:
window_size: 5
send_every: 1

See boards/ for complete, ready-to-flash board configs — e.g. boards/esp32s3-atoms3r.yaml for the recommended M5Stack AtomS3R (PSRAM + esp_tsdb + tuned UART buffers).


See also: Web Server & API · Wiring · Troubleshooting · ← Back to README