spec/fixtures/service_env_contract.yml
Rama develop · réplica de lectura del repositorio original.
# Contract between HELIOS's exporters and the services they configure.
#
# For every managed service (Export::Compose::SERVICE_ORDER) this lists the
# environment variables the service ACTUALLY reads — taken from its source, not
# from its documentation. service_env_contract_spec.rb checks the exported
# compose.yaml against it in both directions:
#
# * every variable an exporter emits is one the service reads
# * every variable the service needs is emitted
#
# This is what catches the class of bug where both sides drift apart silently:
# a collector that defaults an unknown variable (importing to the wrong
# measurement), or one that reads a name HELIOS never writes.
#
# `reads` — exact variable names the service consumes
# `patterns` — dynamically built names (glob), e.g. MAPPING_0_TOPIC
# `requires` — must always be emitted; the service fails or misbehaves without it
# `tolerated` — knowingly emitted but never read (with a reason); keeps the
# gap visible instead of silently widening the `reads` list
#
# When a service gains or loses a variable upstream, update it here.
dashboard:
upstream: solectrus/config/application.rb, config/database.yml, app/lib/sensor/config.rb
reads:
- TZ
- APP_HOST
- FRAME_ANCESTORS
- PLAUSIBLE_URL
- HONEYBADGER_API_KEY
- RORVSWILD_API_KEY
- CO2_EMISSION_FACTOR
- CURRENCY
- INFLUX_SCHEMA
- INFLUX_HOST
- INFLUX_PORT
- INFLUX_ORG
- INFLUX_BUCKET
- INFLUX_TOKEN
- INFLUX_EXCLUDE_FROM_HOUSE_POWER
- INSTALLATION_DATE
- ADMIN_PASSWORD
- LOCKUP_CODEWORD
- UI_THEME
- NOMINATIM_URL # an empty value turns the address lookup off
- SKIP_BROWSER_CHECK
- REDIS_URL
- DB_HOST
- DB_PORT
- DB_USER
- DB_PASSWORD
- RAILS_MAX_THREADS
- RAILS_LOG_LEVEL
- PORT
- ASSET_HOST
- FORCE_SSL
- TRUSTED_PROXY_RANGES
- SECRET_KEY_BASE # read by Rails itself, not by app code
- WEB_CONCURRENCY # read by Puma itself (worker count), not by puma.rb
patterns:
- INFLUX_SENSOR_* # app/lib/sensor/config.rb — one per sensor in the registry
requires:
- INFLUX_HOST
- INFLUX_TOKEN
- INFLUX_ORG
- INFLUX_BUCKET
- DB_HOST
- DB_USER
- DB_PASSWORD
ingest:
upstream: ingest/app/lib/influx_writer.rb, app/lib/sensor_env_config.rb
reads:
- TZ
- INFLUX_HOST
- INFLUX_PORT
- INFLUX_SCHEMA
- INFLUX_ORG # unused by ingest itself, but harmless; see notes below
- INFLUX_BUCKET
- INFLUX_EXCLUDE_FROM_HOUSE_POWER
- RETENTION_HOURS
- STATS_PASSWORD
- APP_ENV
patterns:
- INFLUX_SENSOR_* # app/lib/sensor_env_config.rb KEYS
requires:
- INFLUX_HOST
# Ingest authenticates each write with the token the caller passes in the
# Authorization header, so it deliberately gets no INFLUX_TOKEN.
mqtt-collector:
upstream: mqtt-collector/lib/config.rb
reads:
- TZ
- MQTT_HOST
- MQTT_PORT
- MQTT_SSL
- MQTT_USERNAME
- MQTT_PASSWORD
- INFLUX_HOST
- INFLUX_PORT
- INFLUX_SCHEMA
- INFLUX_TOKEN
- INFLUX_ORG
- INFLUX_BUCKET
patterns:
- MAPPING_*
requires:
- MQTT_HOST
- MQTT_PORT # env.fetch without a fallback — absent means KeyError
- INFLUX_HOST
- INFLUX_TOKEN
- INFLUX_ORG
- INFLUX_BUCKET
senec-collector:
upstream: senec-collector/lib/config.rb
reads:
- TZ
- SENEC_ADAPTER
- SENEC_HOST
- SENEC_SCHEMA
- SENEC_LANGUAGE
- SENEC_INTERVAL
- SENEC_IGNORE
- SENEC_REQUEST_MODE
- SENEC_USERNAME
- SENEC_PASSWORD
- SENEC_TOTP_URI
- SENEC_SYSTEM_ID
- INFLUX_HOST
- INFLUX_PORT
- INFLUX_SCHEMA
- INFLUX_TOKEN
- INFLUX_ORG
- INFLUX_BUCKET
- INFLUX_MEASUREMENT # NOT INFLUX_MEASUREMENT_SENEC — that is the .env name only
requires:
- INFLUX_HOST
- INFLUX_TOKEN
- INFLUX_ORG
- INFLUX_BUCKET
forecast-collector:
upstream: forecast-collector/app/config.rb, app/config/*.rb
reads:
- TZ
- FORECAST_PROVIDER
- FORECAST_CONFIGURATIONS
- FORECAST_INTERVAL
- FORECAST_LATITUDE
- FORECAST_LONGITUDE
- FORECAST_DECLINATION
- FORECAST_AZIMUTH
- FORECAST_KWP
- FORECAST_DAMPING_MORNING
- FORECAST_DAMPING_EVENING
- FORECAST_INVERTER # kilowatts, not watts
- FORECAST_HORIZON
- FORECAST_SOLAR_APIKEY
- SOLCAST_SITE
- SOLCAST_APIKEY
- PVNODE_SITE_ID
- PVNODE_APIKEY
- PVNODE_PAID
- PVNODE_REQUEST_LIMIT
- PVNODE_EXTRA_PARAMS
- INFLUX_HOST
- INFLUX_PORT
- INFLUX_SCHEMA
- INFLUX_TOKEN
- INFLUX_ORG
- INFLUX_BUCKET
- INFLUX_MEASUREMENT
patterns:
- FORECAST_*_LATITUDE
- FORECAST_*_LONGITUDE
- FORECAST_*_DECLINATION
- FORECAST_*_AZIMUTH
- FORECAST_*_KWP
- FORECAST_*_DAMPING_MORNING
- FORECAST_*_DAMPING_EVENING
- FORECAST_*_INVERTER
- FORECAST_*_HORIZON
- SOLCAST_*_SITE
- PVNODE_*_EXTRA_PARAMS
requires:
- INFLUX_HOST
- INFLUX_TOKEN
- INFLUX_ORG
- INFLUX_BUCKET
tibber-collector:
upstream: tibber-collector/app/config.rb
reads:
- TZ
- TIBBER_TOKEN
- TIBBER_INTERVAL
- INFLUX_HOST
- INFLUX_PORT
- INFLUX_SCHEMA
- INFLUX_TOKEN
- INFLUX_ORG
- INFLUX_BUCKET
- INFLUX_MEASUREMENT # NOT INFLUX_MEASUREMENT_PRICES — that is the .env name only
requires:
- TIBBER_TOKEN
- INFLUX_HOST
- INFLUX_TOKEN
- INFLUX_ORG
- INFLUX_BUCKET
public-data-collector:
upstream: public-data-collector/lib/config.rb, lib/providers/*/provider.rb, lib/providers/country.rb
reads:
- TZ
- COUNTRY
- INTERVAL
- ENABLE_FUEL # Providers::Base reads <switch> of each provider
- ENABLE_GAS
- ENABLE_PUBLIC_GRID
- BIDDING_ZONE
- INFLUX_HOST
- INFLUX_PORT
- INFLUX_SCHEMA
- INFLUX_TOKEN
- INFLUX_ORG
- INFLUX_BUCKET
requires:
- COUNTRY # Env::Error without it
- ENABLE_FUEL # at least one source must be on
- INFLUX_HOST
- INFLUX_TOKEN
- INFLUX_ORG
- INFLUX_BUCKET
senec-charger:
upstream: senec-charger/app/config.rb
reads:
- TZ
- SENEC_HOST
- SENEC_SCHEMA
- CHARGER_INTERVAL
- CHARGER_PRICE_MAX
- CHARGER_PRICE_TIME_RANGE
- CHARGER_FORECAST_THRESHOLD
- CHARGER_DRY_RUN
- INFLUX_HOST
- INFLUX_PORT
- INFLUX_SCHEMA
- INFLUX_TOKEN
- INFLUX_ORG
- INFLUX_BUCKET
- INFLUX_MEASUREMENT_PRICES # read directly, unlike the collectors' INFLUX_MEASUREMENT
- INFLUX_MEASUREMENT_FORECAST
requires:
- SENEC_HOST
- INFLUX_HOST
- INFLUX_TOKEN
- INFLUX_ORG
- INFLUX_BUCKET
shelly-collector:
upstream: shelly-collector/lib/config.rb
reads:
- TZ
- SHELLY_HOST
- SHELLY_PASSWORD
- SHELLY_CLOUD_SERVER
- SHELLY_DEVICE_ID
- SHELLY_AUTH_KEY
- SHELLY_INTERVAL
- SHELLY_INVERT_POWER
- INFLUX_HOST
- INFLUX_PORT
- INFLUX_SCHEMA
- INFLUX_TOKEN
- INFLUX_ORG
- INFLUX_BUCKET
- INFLUX_MEASUREMENT
- INFLUX_MODE
- INFLUX_POWER_DATA_TYPE
requires:
- INFLUX_HOST
- INFLUX_TOKEN
- INFLUX_ORG
power-splitter:
upstream: power-splitter/lib/config.rb
reads:
- TZ
- INSTALLATION_DATE
- POWER_SPLITTER_INTERVAL
- INFLUX_HOST
- INFLUX_PORT
- INFLUX_SCHEMA
- INFLUX_TOKEN
- INFLUX_ORG
- INFLUX_BUCKET
- INFLUX_EXCLUDE_FROM_HOUSE_POWER
- REDIS_URL
- DB_HOST
- DB_USER
- DB_PASSWORD
patterns:
# The splitter only knows grid_import_power, house_power, heatpump_power,
# wallbox_power, battery_charging_power and custom_power_01..20
# (lib/config.rb SENSOR_NAMES). HELIOS emits the whole sensor block; the
# extra names are simply ignored, so they stay tolerated rather than
# tightening the exporter and risking a sensor the splitter does need.
- INFLUX_SENSOR_*
requires:
- INFLUX_SENSOR_GRID_IMPORT_POWER # Config::Error without it
- INFLUX_SENSOR_HOUSE_POWER # Config::Error without it
- INFLUX_HOST
- INFLUX_TOKEN
- INFLUX_ORG
- INFLUX_BUCKET
tolerated:
# HELIOS wires the splitter to Postgres via DB_PASSWORD=${POSTGRES_PASSWORD};
# the bare POSTGRES_PASSWORD passthrough is what that reference resolves to.
- POSTGRES_PASSWORD
# csv-importer is not a compose service — CsvImportRunner starts it with
# `docker run -e`. Checked separately by the spec.
csv-importer:
upstream: csv-importer/app/config.rb
reads:
- TZ
- IMPORT_FOLDER
- IMPORT_PAUSE
- SENEC_IGNORE
- INFLUX_HOST
- INFLUX_PORT
- INFLUX_SCHEMA
- INFLUX_TOKEN
- INFLUX_TOKEN_WRITE
- INFLUX_ORG
- INFLUX_BUCKET
- INFLUX_OPEN_TIMEOUT
- INFLUX_READ_TIMEOUT
- INFLUX_WRITE_TIMEOUT
- INFLUX_SENSOR_INVERTER_POWER
- INFLUX_SENSOR_HOUSE_POWER
- INFLUX_SENSOR_GRID_IMPORT_POWER
- INFLUX_SENSOR_GRID_EXPORT_POWER
- INFLUX_SENSOR_BATTERY_CHARGING_POWER
- INFLUX_SENSOR_BATTERY_DISCHARGING_POWER
- INFLUX_SENSOR_BATTERY_SOC
# Third-party images: the variables come from the upstream image, not from a
# SOLECTRUS source we can read. Listed so a new service cannot slip past the
# spec unnoticed, but only checked for unknown names.
influxdb:
upstream: docker.io/influxdb (entrypoint)
third_party: true
reads:
- TZ
- DOCKER_INFLUXDB_INIT_MODE
- DOCKER_INFLUXDB_INIT_USERNAME
- DOCKER_INFLUXDB_INIT_PASSWORD
- DOCKER_INFLUXDB_INIT_ORG
- DOCKER_INFLUXDB_INIT_BUCKET
- DOCKER_INFLUXDB_INIT_ADMIN_TOKEN
- INFLUXD_METRICS_DISABLED
postgresql:
upstream: docker.io/postgres (entrypoint)
third_party: true
reads:
- TZ
- POSTGRES_DB
- POSTGRES_PASSWORD
- POSTGRES_USER
redis:
upstream: docker.io/redis
third_party: true
reads:
- TZ
mosquitto:
upstream: docker.io/eclipse-mosquitto (read by the generated command, not by the broker itself)
third_party: true
reads:
- TZ
- MQTT_PASSWORD
- MQTT_USERNAME
traefik:
upstream: docker.io/traefik (configured via CLI flags and labels, not env)
third_party: true
reads:
- TZ
watchtower:
upstream: nickfedor/watchtower
third_party: true
reads:
- TZ
- WATCHTOWER_CLEANUP
- WATCHTOWER_POLL_INTERVAL
- WATCHTOWER_SCHEDULE
- WATCHTOWER_SCOPE
- WATCHTOWER_TIMEOUT
helios:
upstream: this app (config/application.rb, config/environments/production.rb)
reads:
- TZ
- ADMIN_PASSWORD
- SECRET_KEY_BASE
- FORCE_SSL