The response has been limited to 50k tokens of the smallest files in the repo. You can remove this limitation by removing the max tokens filter.
├── .cursorrules
├── .devcontainer
    └── devcontainer.json
├── .dockerignore
├── .editorconfig
├── .github
    ├── CODEOWNERS
    ├── FUNDING.yml
    ├── ISSUE_TEMPLATE
    │   ├── bug_report.yaml
    │   ├── config.yml
    │   └── feature_request.md
    ├── copilot-instructions.md
    ├── dependabot.yml
    ├── issue_label_bot.yaml
    └── workflows
    │   ├── _claude-issue-triage.yml_
    │   ├── codeql.yml
    │   ├── default.yml
    │   ├── docs-issue.yml
    │   ├── documentation.yml
    │   ├── language-reminder.yml
    │   ├── nightly.yml
    │   ├── openapi-validate.yml
    │   ├── release.yml
    │   ├── schema.yml
    │   ├── stale.yaml
    │   └── website.yml
├── .gitignore
├── .golangci.yml
├── .goreleaser-nightly.yml
├── .goreleaser.yml
├── .prettierignore
├── .storybook
    ├── main.ts
    └── preview.ts
├── .vscode
    └── extensions.json
├── AGENTS.md
├── CONTRIBUTING.md
├── Dockerfile
├── LICENSE
├── LICENSES
    ├── dependencies.md
    ├── exclusions.md
    ├── fonts.md
    └── icons.md
├── Makefile
├── README.md
├── api
    ├── actionconfig.go
    ├── actionconfig_test.go
    ├── api.go
    ├── batterymode.go
    ├── batterymode_enumer.go
    ├── chargemode.go
    ├── chargemodestatus.go
    ├── error.go
    ├── feature.go
    ├── feature_enumer.go
    ├── globalconfig
    │   └── types.go
    ├── marshal.go
    ├── mock.go
    ├── plans.go
    ├── plugin.go
    ├── proto
    │   ├── auth.proto
    │   ├── pb
    │   │   ├── auth.pb.go
    │   │   ├── auth_grpc.pb.go
    │   │   ├── vehicle.pb.go
    │   │   ├── vehicle_grpc.pb.go
    │   │   ├── victron.pb.go
    │   │   └── victron_grpc.pb.go
    │   ├── vehicle.proto
    │   └── victron.proto
    ├── rates.go
    ├── rates_test.go
    ├── reason.go
    ├── reason_enumer.go
    ├── store
    │   └── types.go
    ├── tariff.go
    ├── tarifftype_enumer.go
    └── tariffusage_enumer.go
├── assets
    ├── css
    │   └── app.css
    ├── font
    │   ├── Montserrat-Bold.woff2
    │   └── Montserrat-Medium.woff2
    ├── github
    │   ├── evcc-gopher.png
    │   └── screenshot.webp
    ├── index.html
    ├── js
    │   ├── api.ts
    │   ├── app.ts
    │   ├── colors.ts
    │   ├── components
    │   │   ├── Auth
    │   │   │   ├── LoginModal.vue
    │   │   │   ├── PasswordInput.vue
    │   │   │   ├── PasswordModal.vue
    │   │   │   └── auth.ts
    │   │   ├── Battery
    │   │   │   └── BatterySettingsModal.vue
    │   │   ├── ChargingPlans
    │   │   │   ├── Arrival.vue
    │   │   │   ├── ChargingPlan.stories.ts
    │   │   │   ├── ChargingPlan.vue
    │   │   │   ├── PlanRepeatingSettings.vue
    │   │   │   ├── PlanStaticSettings.vue
    │   │   │   ├── PlansRepeatingSettings.vue
    │   │   │   ├── PlansSettings.vue
    │   │   │   ├── PreconditionSelect.vue
    │   │   │   ├── Preview.stories.ts
    │   │   │   ├── Preview.test.ts
    │   │   │   ├── Preview.vue
    │   │   │   ├── Warnings.vue
    │   │   │   └── types.d.ts
    │   │   ├── Config
    │   │   │   ├── BackupRestoreModal.vue
    │   │   │   ├── ChargerModal.vue
    │   │   │   ├── CircuitsModal.vue
    │   │   │   ├── ControlModal.vue
    │   │   │   ├── DeviceCard.vue
    │   │   │   ├── DeviceModal
    │   │   │   │   ├── Actions.vue
    │   │   │   │   ├── DeviceModalBase.vue
    │   │   │   │   ├── Modbus.vue
    │   │   │   │   ├── SponsorTokenRequired.vue
    │   │   │   │   ├── TemplateSelector.vue
    │   │   │   │   ├── YamlEntry.vue
    │   │   │   │   └── index.ts
    │   │   │   ├── DeviceTags.vue
    │   │   │   ├── EebusModal.vue
    │   │   │   ├── ExperimentalBanner.vue
    │   │   │   ├── FormRow.vue
    │   │   │   ├── GeneralConfig.vue
    │   │   │   ├── GeneralConfigEntry.vue
    │   │   │   ├── HemsModal.vue
    │   │   │   ├── InfluxModal.vue
    │   │   │   ├── JsonModal.vue
    │   │   │   ├── LoadpointModal.vue
    │   │   │   ├── Markdown.vue
    │   │   │   ├── MessagingModal.vue
    │   │   │   ├── MeterCard.vue
    │   │   │   ├── MeterModal.vue
    │   │   │   ├── ModbusProxyModal.vue
    │   │   │   ├── MqttModal.vue
    │   │   │   ├── NetworkModal.vue
    │   │   │   ├── NewDeviceButton.vue
    │   │   │   ├── PropertyCertField.vue
    │   │   │   ├── PropertyCollapsible.vue
    │   │   │   ├── PropertyEntry.vue
    │   │   │   ├── PropertyField.vue
    │   │   │   ├── PropertyFileField.vue
    │   │   │   ├── ShmModal.vue
    │   │   │   ├── SponsorModal.vue
    │   │   │   ├── TariffsModal.vue
    │   │   │   ├── TelemetryModal.vue
    │   │   │   ├── TestResult.vue
    │   │   │   ├── TitleModal.vue
    │   │   │   ├── VehicleModal.vue
    │   │   │   ├── WelcomeBanner.vue
    │   │   │   ├── YamlEditor.vue
    │   │   │   ├── YamlEditorContainer.vue
    │   │   │   ├── YamlModal.vue
    │   │   │   ├── defaultYaml
    │   │   │   │   ├── circuits.yaml
    │   │   │   │   ├── customCharger.yaml
    │   │   │   │   ├── customHeater.yaml
    │   │   │   │   ├── eebus.yaml
    │   │   │   │   ├── heatpump.yaml
    │   │   │   │   ├── hems.yaml
    │   │   │   │   ├── messaging.yaml
    │   │   │   │   ├── meter.yaml
    │   │   │   │   ├── modbusproxy.yaml
    │   │   │   │   ├── sgready.yaml
    │   │   │   │   ├── sgreadyRelay.yaml
    │   │   │   │   ├── switchsocketCharger.yaml
    │   │   │   │   ├── switchsocketHeater.yaml
    │   │   │   │   ├── tariffs.yaml
    │   │   │   │   └── vehicle.yaml
    │   │   │   ├── mixins
    │   │   │   │   └── test.js
    │   │   │   └── utils
    │   │   │   │   └── test.ts
    │   │   ├── Energyflow
    │   │   │   ├── BatteryIcon.stories.ts
    │   │   │   ├── BatteryIcon.vue
    │   │   │   ├── Energyflow.stories.ts
    │   │   │   ├── Energyflow.vue
    │   │   │   ├── Entry.vue
    │   │   │   ├── LabelBar.vue
    │   │   │   └── Visualization.vue
    │   │   ├── Footer
    │   │   │   ├── Footer.stories.ts
    │   │   │   ├── Footer.vue
    │   │   │   ├── Logo.vue
    │   │   │   ├── OfflineIndicator.stories.ts
    │   │   │   ├── OfflineIndicator.vue
    │   │   │   ├── RestartButton.vue
    │   │   │   ├── Version.stories.ts
    │   │   │   └── Version.vue
    │   │   ├── Forecast
    │   │   │   ├── ActiveSlot.vue
    │   │   │   ├── Chart.vue
    │   │   │   ├── Details.vue
    │   │   │   ├── ForecastModal.vue
    │   │   │   ├── TypeSelect.vue
    │   │   │   └── types.ts
    │   │   ├── GlobalSettings
    │   │   │   ├── GlobalSettingsModal.vue
    │   │   │   ├── LoadpointOrderSettings.vue
    │   │   │   └── UserInterfaceSettings.vue
    │   │   ├── HelpModal.vue
    │   │   ├── Helper
    │   │   │   ├── AnimatedNumber.vue
    │   │   │   ├── CopyButton.vue
    │   │   │   ├── CustomSelect.vue
    │   │   │   ├── DragDropItem.vue
    │   │   │   ├── DragDropList.vue
    │   │   │   ├── FormRow.vue
    │   │   │   ├── GenericModal.vue
    │   │   │   ├── IconSelectGroup.vue
    │   │   │   ├── IconSelectItem.vue
    │   │   │   ├── LabelAndValue.vue
    │   │   │   ├── MultiSelect.vue
    │   │   │   ├── SelectGroup.story.vue
    │   │   │   └── SelectGroup.vue
    │   │   ├── HemsWarning.vue
    │   │   ├── Issue
    │   │   │   ├── AdditionalItem.vue
    │   │   │   ├── SummaryModal.vue
    │   │   │   ├── format.test.ts
    │   │   │   ├── format.ts
    │   │   │   ├── template.test.ts
    │   │   │   ├── template.ts
    │   │   │   └── types.d.ts
    │   │   ├── Loadpoints
    │   │   │   ├── Loadpoint.stories.ts
    │   │   │   ├── Loadpoint.vue
    │   │   │   ├── Loadpoints.stories.ts
    │   │   │   ├── Loadpoints.vue
    │   │   │   ├── Mode.stories.ts
    │   │   │   ├── Mode.vue
    │   │   │   ├── Phases.stories.ts
    │   │   │   ├── Phases.vue
    │   │   │   ├── SessionInfo.vue
    │   │   │   ├── SettingsBatteryBoost.vue
    │   │   │   ├── SettingsButton.vue
    │   │   │   └── SettingsModal.vue
    │   │   ├── MaterialIcon
    │   │   │   ├── Add.vue
    │   │   │   ├── BatteryBoost.vue
    │   │   │   ├── Circuits.vue
    │   │   │   ├── Climater.vue
    │   │   │   ├── CloudOffline.vue
    │   │   │   ├── Dropdown.vue
    │   │   │   ├── DynamicPrice.vue
    │   │   │   ├── Edit.vue
    │   │   │   ├── Eebus.vue
    │   │   │   ├── Forecast.vue
    │   │   │   ├── Hems.vue
    │   │   │   ├── Influx.vue
    │   │   │   ├── Loadpoint.vue
    │   │   │   ├── MaterialIcon.story.ts
    │   │   │   ├── ModbusProxy.vue
    │   │   │   ├── Mqtt.vue
    │   │   │   ├── Notification.vue
    │   │   │   ├── PlanEnd.vue
    │   │   │   ├── PlanStart.vue
    │   │   │   ├── Play.vue
    │   │   │   ├── Question.vue
    │   │   │   ├── Reconnect.vue
    │   │   │   ├── Record.vue
    │   │   │   ├── Restart.vue
    │   │   │   ├── RfidWait.vue
    │   │   │   ├── Shm.vue
    │   │   │   ├── SunDown.vue
    │   │   │   ├── SunPause.vue
    │   │   │   ├── SunUp.vue
    │   │   │   ├── Sync.vue
    │   │   │   ├── TempLimit.vue
    │   │   │   ├── Total.vue
    │   │   │   ├── VehicleLimit.vue
    │   │   │   ├── VehicleLimitReached.vue
    │   │   │   ├── VehicleLimitWarning.vue
    │   │   │   ├── VehicleMinSoc.vue
    │   │   │   └── Welcome.vue
    │   │   ├── MultiIcon
    │   │   │   ├── 1.vue
    │   │   │   ├── 2.vue
    │   │   │   ├── 3.vue
    │   │   │   ├── 4.vue
    │   │   │   ├── 5.vue
    │   │   │   ├── 6.vue
    │   │   │   ├── 7.vue
    │   │   │   ├── 8.vue
    │   │   │   ├── 9.vue
    │   │   │   ├── MultiIcon.stories.ts
    │   │   │   ├── MultiIcon.vue
    │   │   │   ├── Plus.vue
    │   │   │   └── index.ts
    │   │   ├── Optimize
    │   │   │   ├── BatteryConfigurationTable.vue
    │   │   │   ├── ChargeChart.vue
    │   │   │   ├── CopyButton.vue
    │   │   │   ├── PriceChart.vue
    │   │   │   ├── SocChart.vue
    │   │   │   ├── TimeSeriesDataTable.vue
    │   │   │   └── compactJson.ts
    │   │   ├── Savings
    │   │   │   ├── LiveCommunity.stories.ts
    │   │   │   ├── LiveCommunity.vue
    │   │   │   ├── Savings.vue
    │   │   │   ├── Sponsor.stories.ts
    │   │   │   ├── Sponsor.vue
    │   │   │   ├── SponsorTokenExpires.stories.ts
    │   │   │   ├── SponsorTokenExpires.vue
    │   │   │   ├── Tile.stories.ts
    │   │   │   ├── Tile.vue
    │   │   │   ├── co2Reference.ts
    │   │   │   ├── communityApi.ts
    │   │   │   └── types.d.ts
    │   │   ├── Sessions
    │   │   │   ├── AvgCostGroupedChart.vue
    │   │   │   ├── CostGroupedChart.vue
    │   │   │   ├── CostHistoryChart.vue
    │   │   │   ├── DateNavigator.vue
    │   │   │   ├── DateNavigatorButton.vue
    │   │   │   ├── EnergyGroupedChart.vue
    │   │   │   ├── EnergyHistoryChart.vue
    │   │   │   ├── LegendList.vue
    │   │   │   ├── PeriodSelector.vue
    │   │   │   ├── SessionDetailsModal.vue
    │   │   │   ├── SessionTable.vue
    │   │   │   ├── SolarGroupedChart.vue
    │   │   │   ├── SolarYearChart.vue
    │   │   │   ├── chartConfig.ts
    │   │   │   └── types.ts
    │   │   ├── Site
    │   │   │   ├── Site.vue
    │   │   │   ├── WelcomeIcons.vue
    │   │   │   └── types.d.ts
    │   │   ├── Tariff
    │   │   │   ├── SmartCostLimit.vue
    │   │   │   ├── SmartFeedInPriority.vue
    │   │   │   ├── SmartTariffBase.vue
    │   │   │   └── TariffChart.vue
    │   │   ├── TelemetrySettings.vue
    │   │   ├── Top
    │   │   │   ├── Header.vue
    │   │   │   ├── Navigation.stories.ts
    │   │   │   ├── Navigation.vue
    │   │   │   ├── Notifications.stories.ts
    │   │   │   ├── Notifications.vue
    │   │   │   ├── baseapi.ts
    │   │   │   └── types.d.ts
    │   │   ├── VehicleIcon
    │   │   │   ├── Airpurifier.vue
    │   │   │   ├── Battery.vue
    │   │   │   ├── Bike.vue
    │   │   │   ├── Bulb.vue
    │   │   │   ├── Bus.vue
    │   │   │   ├── Climate.vue
    │   │   │   ├── Coffeemaker.vue
    │   │   │   ├── Compute.vue
    │   │   │   ├── Cooking.vue
    │   │   │   ├── Cooler.vue
    │   │   │   ├── Desktop.vue
    │   │   │   ├── Device.vue
    │   │   │   ├── Dishwasher.vue
    │   │   │   ├── Dryer.vue
    │   │   │   ├── Floorlamp.vue
    │   │   │   ├── Generic.vue
    │   │   │   ├── Heater.vue
    │   │   │   ├── Heatexchange.vue
    │   │   │   ├── Heatpump.vue
    │   │   │   ├── Kettle.vue
    │   │   │   ├── Laundry.vue
    │   │   │   ├── Laundry2.vue
    │   │   │   ├── Machine.vue
    │   │   │   ├── Meter.vue
    │   │   │   ├── Microwave.vue
    │   │   │   ├── Moped.vue
    │   │   │   ├── Motorcycle.vue
    │   │   │   ├── Pump.vue
    │   │   │   ├── Rickshaw.vue
    │   │   │   ├── Rocket.vue
    │   │   │   ├── Scooter.vue
    │   │   │   ├── Shuttle.vue
    │   │   │   ├── SmartConsumer.vue
    │   │   │   ├── Taxi.vue
    │   │   │   ├── Tool.vue
    │   │   │   ├── Tractor.vue
    │   │   │   ├── Van.vue
    │   │   │   ├── VehicleIcon.stories.ts
    │   │   │   ├── VehicleIcon.vue
    │   │   │   ├── WaterHeater.vue
    │   │   │   └── index.ts
    │   │   └── Vehicles
    │   │   │   ├── LimitEnergySelect.vue
    │   │   │   ├── LimitSocSelect.vue
    │   │   │   ├── Options.vue
    │   │   │   ├── Soc.vue
    │   │   │   ├── Status.story.vue
    │   │   │   ├── Status.test.ts
    │   │   │   ├── Status.vue
    │   │   │   ├── StatusItem.vue
    │   │   │   ├── Title.vue
    │   │   │   ├── Vehicle.stories.ts
    │   │   │   └── Vehicle.vue
    │   ├── experimental.js
    │   ├── featureflags.ts
    │   ├── i18n.ts
    │   ├── mixins
    │   │   ├── breakpoint.ts
    │   │   ├── collector.ts
    │   │   ├── formatter.test.ts
    │   │   ├── formatter.ts
    │   │   └── icon.ts
    │   ├── restart.ts
    │   ├── router.ts
    │   ├── settings.ts
    │   ├── store.ts
    │   ├── theme.ts
    │   ├── types
    │   │   ├── evcc.ts
    │   │   ├── shopicons.d.ts
    │   │   └── vue.d.ts
    │   ├── uiLoadpoints.ts
    │   ├── units.ts
    │   ├── utils
    │   │   ├── cleanYaml.test.ts
    │   │   ├── cleanYaml.ts
    │   │   ├── convertRates.ts
    │   │   ├── debounce.ts
    │   │   ├── deepClone.ts
    │   │   ├── deepEqual.ts
    │   │   ├── energyOptions.ts
    │   │   ├── fatal.ts
    │   │   ├── forecast.test.ts
    │   │   ├── forecast.ts
    │   │   ├── log.ts
    │   │   ├── native.ts
    │   │   ├── sleep.ts
    │   │   └── useDebouncedComputed.ts
    │   └── views
    │   │   ├── App.vue
    │   │   ├── Config.vue
    │   │   ├── Energy.vue
    │   │   ├── Issue.vue
    │   │   ├── Log.vue
    │   │   ├── Main.vue
    │   │   ├── Optimize.vue
    │   │   └── Sessions.vue
    └── public
    │   └── meta
    │       ├── android-chrome-192x192-maskable.png
    │       ├── android-chrome-192x192.png
    │       ├── android-chrome-512x512-maskable.png
    │       ├── android-chrome-512x512.png
    │       ├── android-chrome-maskable.svg
    │       ├── android-chrome-monochrome.svg
    │       ├── android-chrome.svg
    │       ├── apple-touch-icon.png
    │       ├── browserconfig.xml
    │       ├── favicon-16x16.png
    │       ├── favicon-32x32.png
    │       ├── favicon.ico
    │       ├── mstile-144x144.png
    │       ├── mstile-150x150.png
    │       ├── mstile-310x150.png
    │       ├── mstile-310x310.png
    │       ├── mstile-70x70.png
    │       ├── safari-pinned-tab.svg
    │       └── site.webmanifest
├── charger
    ├── _blueprint.go
    ├── abb.go
    ├── abl-em4.go
    ├── abl.go
    ├── abl_decorators.go
    ├── alfen.go
    ├── alfen_decorators.go
    ├── alphatec.go
    ├── alpitronic.go
    ├── amperfied.go
    ├── amperfied_decorators.go
    ├── bender.go
    ├── bender_decorators.go
    ├── cfos.go
    ├── cfos_decorators.go
    ├── charger.go
    ├── charger_decorators.go
    ├── compleo.go
    ├── config.go
    ├── config
    │   └── config.go
    ├── connectiq.go
    ├── connectiq
    │   └── types.go
    ├── dadapower.go
    ├── daheimladen.go
    ├── daheimladen_decorators.go
    ├── delta.go
    ├── easee.go
    ├── easee
    │   ├── identity.go
    │   ├── log.go
    │   ├── observationid_enumer.go
    │   ├── signalr.go
    │   └── types.go
    ├── easee_test.go
    ├── echarge
    │   ├── ecb1
    │   │   └── types.go
    │   ├── salia
    │   │   ├── types.go
    │   │   └── types_test.go
    │   └── types.go
    ├── eebus.go
    ├── eebus_decorators.go
    ├── eebus_test.go
    ├── em2go-duo.go
    ├── em2go.go
    ├── em2go_decorators.go
    ├── embed.go
    ├── eprowallbox.go
    ├── etrel.go
    ├── evecube.go
    ├── evecube_decorators.go
    ├── evse
    │   └── types.go
    ├── evsedin.go
    ├── evsedin_decorators.go
    ├── evsewifi.go
    ├── evsewifi_decorators.go
    ├── evsewifi_test.go
    ├── fritzdect.go
    ├── fronius-wattpilot.go
    ├── go-e.go
    ├── go-e
    │   ├── api.go
    │   ├── api_test.go
    │   ├── types.go
    │   └── types2.go
    ├── go-e_decorators.go
    ├── go-e_test.go
    ├── hardybarth-ecb1.go
    ├── hardybarth-salia.go
    ├── hardybarth-salia_decorators.go
    ├── heatpump.go
    ├── heatpump_decorators.go
    ├── heidelberg-ec.go
    ├── helper.go
    ├── hesotec.go
    ├── homeassistant-switch.go
    ├── homeassistant.go
    ├── homeassistant_decorators.go
    ├── homematic.go
    ├── homewizard.go
    ├── innogy.go
    ├── innogy_decorators.go
    ├── kathrein.go
    ├── keba-modbus.go
    ├── keba-modbus_decorators.go
    ├── keba-udp.go
    ├── keba-udp_decorators.go
    ├── keba
    │   ├── listener.go
    │   ├── sender.go
    │   └── types.go
    ├── kse.go
    ├── kse_decorators.go
    ├── measurement
    │   ├── energy.go
    │   └── heating.go
    ├── mennekes-compact.go
    ├── mennekes-compact_decorators.go
    ├── mennekes-hcc3.go
    ├── mypv.go
    ├── mystrom.go
    ├── nrg
    │   ├── ble
    │   │   ├── nrg_linux.go
    │   │   └── types.go
    │   └── connect
    │   │   └── types.go
    ├── nrgble.go
    ├── nrgble_linux.go
    ├── nrgconnect.go
    ├── nrggen2.go
    ├── nrggen2_decorators.go
    ├── obo.go
    ├── ocpp.go
    ├── ocpp
    │   ├── connector.go
    │   ├── connector_core.go
    │   ├── connector_requests.go
    │   ├── connector_test.go
    │   ├── const.go
    │   ├── cp.go
    │   ├── cp_core.go
    │   ├── cp_requests.go
    │   ├── cp_setup.go
    │   ├── cs.go
    │   ├── cs_core.go
    │   ├── cs_log.go
    │   ├── helper.go
    │   ├── helper_test.go
    │   └── instance.go
    ├── ocpp_decorators.go
    ├── ocpp_test.go
    ├── ocpp_test_handler.go
    ├── ocpp_test_logger.go
    ├── openevse.go
    ├── openevse
    │   └── types.go
    ├── openevse_decorators.go
    ├── openwb-2.0.go
    ├── openwb-2.0_decorators.go
    ├── openwb-pro.go
    ├── openwb-pro_decorators.go
    ├── openwb.go
    ├── openwb
    │   ├── pro
    │   │   └── types.go
    │   └── topics.go
    ├── openwb_decorators.go
    ├── pantabox.go
    ├── pcelectric.go
    ├── pcelectric
    │   └── types.go
    ├── pcelectric_decorators.go
    ├── peblar.go
    ├── peblar_decorators.go
    ├── phoenix-charx.go
    ├── phoenix-charx_decorators.go
    ├── phoenix-em-eth.go
    ├── phoenix-em-eth_decorators.go
    ├── phoenix-ev-eth.go
    ├── phoenix-ev-eth_decorators.go
    ├── phoenix-ev-ser.go
    ├── plugchoice.go
    ├── plugchoice
    │   ├── api.go
    │   └── types.go
    ├── pracht-alpha.go
    ├── pulsares.go
    ├── pulsares_decorators.go
    ├── pulsatrix.go
    ├── schneider-v3.go
    ├── semp.go
    ├── semp
    │   ├── connection.go
    │   └── types.go
    ├── semp_decorators.go
    ├── semp_test.go
    ├── sgready-relay.go
    ├── sgready.go
    ├── sgready_decorators.go
    ├── shelly.go
    ├── shelly_decorators.go
    ├── sigenergy.go
    ├── smaevcharger.go
    ├── smaevcharger
    │   ├── identity.go
    │   └── types.go
    ├── smartevse.go
    ├── solax.go
    ├── sungrow.go
    ├── switchsocket.go
    ├── switchsocket_decorators.go
    ├── tapo.go
    ├── tasmota.go
    ├── tasmota_decorators.go
    ├── template.go
    ├── template_test.go
    ├── tessie.go
    ├── tplink.go
    ├── trydan.go
    ├── twc3.go
    ├── vaillant.go
    ├── vaillant_decorators.go
    ├── vehicle-api.go
    ├── versicharge.go
    ├── vestel.go
    ├── vestel_decorators.go
    ├── victron.go
    ├── wallbe.go
    ├── wallbe_decorators.go
    ├── warp
    │   ├── const.go
    │   ├── externalcontrol_enumer.go
    │   └── types.go
    ├── warp2.go
    ├── warp2_decorators.go
    ├── webasto-next.go
    ├── weidmüller.go
    ├── weidmüller_decorators.go
    ├── zaptec.go
    ├── zaptec
    │   ├── const.go
    │   ├── observationid_enumer.go
    │   └── types.go
    └── zaptec_decorators.go
├── cmd
    ├── cache-clear.go
    ├── cache-get.go
    ├── cache.go
    ├── charger.go
    ├── charger_ramp.go
    ├── check_config.go
    ├── class_enumer.go
    ├── config.go
    ├── config_delete.go
    ├── configure.go
    ├── configure
    │   ├── configure.go
    │   ├── configure.tpl
    │   ├── devicetest.go
    │   ├── eebus.go
    │   ├── flow.go
    │   ├── helper.go
    │   ├── localization
    │   │   ├── de.toml
    │   │   └── en.toml
    │   ├── main.go
    │   ├── survey.go
    │   ├── texts.go
    │   └── types.go
    ├── decorate
    │   ├── decorate.go
    │   ├── decorate.tpl
    │   ├── decorate_decorators.go
    │   └── decorate_test.go
    ├── demo.go
    ├── demo.yaml
    ├── detect.go
    ├── detect
    │   ├── analyze.go
    │   ├── definitions.go
    │   ├── tasklist.go
    │   ├── tasks
    │   │   ├── const.go
    │   │   ├── http.go
    │   │   ├── keba.go
    │   │   ├── modbus.go
    │   │   ├── mqtt.go
    │   │   ├── ping.go
    │   │   ├── registry.go
    │   │   ├── sma.go
    │   │   ├── tcp.go
    │   │   └── types.go
    │   └── work.go
    ├── device.go
    ├── discuss.go
    ├── discuss.tpl
    ├── dump.go
    ├── dump.tpl
    ├── dumper.go
    ├── eebus.go
    ├── error.go
    ├── error_test.go
    ├── flags.go
    ├── gendock.go
    ├── health.go
    ├── helper.go
    ├── meter.go
    ├── migrate.go
    ├── ocpp
    │   ├── handler.go
    │   └── main.go
    ├── openapi
    │   └── openapi.go
    ├── password.go
    ├── password_reset.go
    ├── password_set.go
    ├── password_test.go
    ├── refs.go
    ├── root.go
    ├── root_test.go
    ├── settings-get.go
    ├── settings-set.go
    ├── settings.go
    ├── setup.go
    ├── setup_circuits_test.go
    ├── setup_test.go
    ├── shutdown
    │   └── shutdown.go
    ├── soc
    │   └── main.go
    ├── sponsor.go
    ├── sunspec.go
    ├── tariff.go
    ├── token.go
    ├── token_ford-connect.go
    ├── token_psa.go
    ├── token_tronity.go
    └── vehicle.go
├── core
    ├── circuit
    │   ├── circuit.go
    │   ├── circuit_test.go
    │   └── config.go
    ├── coordinator
    │   ├── adapter.go
    │   ├── api.go
    │   ├── coordinator.go
    │   ├── coordinator_test.go
    │   └── dummy.go
    ├── energy_metrics.go
    ├── energy_metrics_test.go
    ├── health.go
    ├── helper.go
    ├── keys
    │   ├── auth.go
    │   ├── global.go
    │   ├── loadpoint.go
    │   └── site.go
    ├── loadpoint.go
    ├── loadpoint
    │   ├── api.go
    │   ├── config.go
    │   ├── error.go
    │   ├── mock.go
    │   ├── pollmode_enumer.go
    │   └── types.go
    ├── loadpoint_api.go
    ├── loadpoint_charger.go
    ├── loadpoint_effective.go
    ├── loadpoint_effective_test.go
    ├── loadpoint_mutex.go
    ├── loadpoint_phases.go
    ├── loadpoint_phases_test.go
    ├── loadpoint_plan.go
    ├── loadpoint_session.go
    ├── loadpoint_session_test.go
    ├── loadpoint_smartcost.go
    ├── loadpoint_status_test.go
    ├── loadpoint_sync_test.go
    ├── loadpoint_test.go
    ├── loadpoint_vehicle.go
    ├── loadpoint_vehicle_test.go
    ├── meterenergy.go
    ├── meterenergy_test.go
    ├── metrics
    │   ├── db.go
    │   └── types.go
    ├── optimizer.md
    ├── planner
    │   ├── helper.go
    │   ├── helper_test.go
    │   ├── planner.go
    │   ├── planner.md
    │   ├── planner.svg
    │   ├── planner_test.go
    │   ├── sort.go
    │   └── sort_test.go
    ├── prioritizer
    │   ├── prioritizer.go
    │   └── prioritizer_test.go
    ├── progress.go
    ├── progress_test.go
    ├── session
    │   ├── db.go
    │   ├── format_test.go
    │   └── session.go
    ├── settings
    │   ├── config.go
    │   ├── database.go
    │   └── settings.go
    ├── site.go
    ├── site
    │   ├── api.go
    │   └── vehicles.go
    ├── site_api.go
    ├── site_battery.go
    ├── site_battery_test.go
    ├── site_circuit_test.go
    ├── site_circuits.go
    ├── site_optimizer.go
    ├── site_optimizer_test.go
    ├── site_tariffs.go
    ├── site_test.go
    ├── site_vehicles.go
    ├── soc
    │   ├── estimator.go
    │   ├── estimator_test.go
    │   └── helper.go
    ├── solar.go
    ├── solar_test.go
    ├── stats.go
    ├── timer.go
    ├── timer_test.go
    ├── vehicle
    │   ├── adapter.go
    │   ├── api.go
    │   ├── dummy.go
    │   ├── mock.go
    │   └── vehicle.go
    └── wrapper
    │   ├── chargemeter.go
    │   ├── chargemeter_test.go
    │   ├── chargerater.go
    │   ├── chargerater_test.go
    │   ├── chargetimer.go
    │   └── chargetimer_test.go
├── env.d.ts
├── eslint.config.mts
├── evcc.dist.yaml
├── go.mod
├── go.sum
├── hems
    ├── config.go
    ├── eebus
    │   ├── eebus.go
    │   ├── events.go
    │   └── types.go
    ├── relay
    │   └── relay.go
    ├── shared
    │   └── helper.go
    └── shm
    │   ├── messages.go
    │   └── shm.go
├── i18n
    ├── .prettierrc
    ├── ar.json
    ├── bg.json
    ├── ca.json
    ├── check.ts
    ├── cs.json
    ├── da.json
    ├── de.json
    ├── el.json
    ├── en.json
    ├── es.json
    ├── et.json
    ├── fi.json
    ├── fr.json
    ├── hr.json
    ├── hu.json
    ├── it.json
    ├── lb.json
    ├── lt.json
    ├── nl.json
    ├── no.json
    ├── pl.json
    ├── pt.json
    ├── ro.json
    ├── ru.json
    ├── sk.json
    ├── sl.json
    ├── sv.json
    ├── ta.json
    ├── tr.json
    ├── uk.json
    └── zh-Hans.json
├── icon.png
├── jest.config.ts
├── lm.md
├── main.go
├── meter
    ├── _blueprint.go
    ├── bosch
    │   ├── api.go
    │   └── types.go
    ├── bosch_bpts5_hybrid.go
    ├── bosch_bpts5_hybrid_decorators.go
    ├── cfos.go
    ├── config.go
    ├── config
    │   └── config.go
    ├── discovergy.go
    ├── discovergy
    │   └── types.go
    ├── dsmr.go
    ├── dsmr_decorators.go
    ├── e3dc.go
    ├── e3dc_decorators.go
    ├── eebus.go
    ├── eebus_test.go
    ├── fritzdect.go
    ├── fritzdect
    │   └── fritzdect.go
    ├── goodwe-wifi.go
    ├── goodwe-wifi_decorators.go
    ├── goodwe
    │   ├── server.go
    │   └── types.go
    ├── homeassistant.go
    ├── homeassistant_decorators.go
    ├── homematic.go
    ├── homematic
    │   ├── connection.go
    │   ├── types.go
    │   └── types_test.go
    ├── homewizard.go
    ├── homewizard
    │   ├── connection.go
    │   ├── types.go
    │   └── types_test.go
    ├── lgess.go
    ├── lgess_decorators.go
    ├── lgpcs
    │   ├── lgpcs.go
    │   └── types.go
    ├── mbmd.go
    ├── mbmd_decorators.go
    ├── mbmd_operation.go
    ├── measurement
    │   ├── energy.go
    │   └── phases.go
    ├── meter.go
    ├── meter_average.go
    ├── meter_decorators.go
    ├── meter_test.go
    ├── mystrom.go
    ├── mystrom
    │   └── mystrom.go
    ├── obis
    │   └── obis.go
    ├── openwb.go
    ├── powerwall.go
    ├── powerwall_decorators.go
    ├── rct.go
    ├── rct_decorators.go
    ├── shelly.go
    ├── shelly
    │   ├── connection.go
    │   ├── gen1.go
    │   ├── gen1_test.go
    │   ├── gen2.go
    │   ├── gen2_test.go
    │   ├── types.go
    │   └── types_test.go
    ├── shelly_decorators.go
    ├── sma.go
    ├── sma_decorators.go
    ├── tapo.go
    ├── tapo
    │   └── connection.go
    ├── tasmota.go
    ├── tasmota
    │   ├── connection.go
    │   ├── types.go
    │   └── types_test.go
    ├── tasmota_decorators.go
    ├── template.go
    ├── template_test.go
    ├── tibber-pulse.go
    ├── tibber
    │   ├── client.go
    │   └── types.go
    ├── tplink.go
    ├── tplink
    │   ├── connection.go
    │   ├── types.go
    │   └── types_test.go
    ├── tq-em.go
    ├── tq-em420.go
    ├── tq-em_decorators.go
    ├── usage_battery.go
    ├── usage_pv.go
    ├── zendure.go
    ├── zendure
    │   ├── connection.go
    │   ├── connection_test.go
    │   ├── credentials.go
    │   └── types.go
    └── zendure_decorators.go
├── package-lock.json
├── package.json
├── packaging
    ├── docker
    │   └── bin
    │   │   └── entrypoint.sh
    ├── fly.toml
    ├── gokrazy
    │   └── config.tmpl.json
    ├── init
    │   └── evcc.service
    ├── patch
    │   └── asn1.diff
    └── scripts
    │   ├── postinstall.sh
    │   ├── postremove.sh
    │   ├── preinstall.sh
    │   └── preremove.sh
├── playwright.config.ts
├── plugin
    ├── auth
    │   ├── config.go
    │   ├── oauth.go
    │   ├── oauth_test.go
    │   └── viessmann.go
    ├── calc.go
    ├── charger.go
    ├── combined.go
    ├── config.go
    ├── config_test.go
    ├── const.go
    ├── const_test.go
    ├── convert.go
    ├── error.go
    ├── getter.go
    ├── go.go
    ├── golang
    │   ├── registry.go
    │   └── stdlib
    │   │   ├── fmt.go
    │   │   ├── generate.go
    │   │   ├── math.go
    │   │   ├── strings.go
    │   │   └── time.go
    ├── helper.go
    ├── http.go
    ├── http_auth.go
    ├── http_limit.go
    ├── http_test.go
    ├── ignore.go
    ├── javascript.go
    ├── javascript
    │   └── registry.go
    ├── map.go
    ├── meter.go
    ├── method.go
    ├── method_enumer.go
    ├── modbus.go
    ├── mqtt.go
    ├── mqtt
    │   ├── client.go
    │   └── registry.go
    ├── mqtt_handler.go
    ├── mqtt_timeout.go
    ├── pipeline
    │   ├── pipeline.go
    │   └── pipeline_test.go
    ├── prometheus.go
    ├── random.go
    ├── script.go
    ├── sequence.go
    ├── sleep.go
    ├── sma.go
    ├── sma
    │   ├── device.go
    │   └── discover.go
    ├── socket.go
    ├── socket_test.go
    ├── sunspec.go
    ├── sunspec_cache.go
    ├── switch.go
    ├── timeseries.go
    ├── transformation.go
    ├── valid.go
    └── watchdog.go
├── prettier.config.js
├── push
    ├── config.go
    ├── hub.go
    ├── ntfy.go
    ├── push.go
    ├── pushover.go
    ├── shoutrrr.go
    └── telegram.go
├── schema.json
├── server
    ├── assets
    │   ├── assets.go
    │   └── assets_live.go
    ├── db
    │   ├── cache
    │   │   └── cache.go
    │   ├── db.go
    │   ├── log.go
    │   └── settings
    │   │   ├── api.go
    │   │   ├── mock.go
    │   │   ├── setting.go
    │   │   └── settings_test.go
    ├── eebus
    │   ├── certificate.go
    │   ├── connector.go
    │   ├── eebus.go
    │   ├── eebus_test.go
    │   ├── helper.go
    │   └── types.go
    ├── helper.go
    ├── http.go
    ├── http_auth.go
    ├── http_config_device_handler.go
    ├── http_config_helper.go
    ├── http_config_helper_test.go
    ├── http_config_loadpoint_handler.go
    ├── http_config_metadata_handler.go
    ├── http_config_site_handler.go
    ├── http_config_site_other_handler.go
    ├── http_config_yaml_handler.go
    ├── http_global_settings_handler.go
    ├── http_loadpoint_handler.go
    ├── http_session_handler.go
    ├── http_site_handler.go
    ├── http_vehicle_handler.go
    ├── influxdb.go
    ├── influxdb_test.go
    ├── log.go
    ├── mcp
    │   ├── mcp.go
    │   ├── openapi.json
    │   ├── openapi.md
    │   ├── prompt.tpl
    │   └── tools.go
    ├── modbus
    │   ├── handler.go
    │   ├── log.go
    │   ├── proxy.go
    │   ├── proxy_test.go
    │   ├── readonlymode.go
    │   └── readonlymode_enumer.go
    ├── mqtt.go
    ├── mqtt_setter.go
    ├── mqtt_test.go
    ├── openapi.go
    ├── openapi.yaml
    ├── openapi_test.go
    ├── product.go
    ├── providerauth
    │   ├── handler.go
    │   ├── providerauth.go
    │   └── state.go
    ├── socket.go
    ├── socket_helper.go
    ├── socket_test.go
    ├── uds.go
    ├── uds_windows.go
    └── updater
    │   ├── github.go
    │   ├── gokrazy.go
    │   ├── run.go
    │   ├── run_gokrazy.go
    │   └── watch.go
├── tariff
    ├── amber.go
    ├── amber
    │   └── types.go
    ├── awattar.go
    ├── awattar
    │   └── api.go
    ├── combined.go
    ├── combined_test.go
    ├── config.go
    ├── corrently
    │   ├── tokensource.go
    │   └── types.go
    ├── edf-tempo.go
    ├── electricitymaps.go
    ├── elering.go
    ├── elering
    │   └── types.go
    ├── embed.go
    ├── entsoe.go
    ├── entsoe
    │   ├── api.go
    │   ├── areas.go
    │   └── static.go
    ├── fixed.go
    ├── fixed
    │   ├── day.go
    │   ├── day_enumer.go
    │   ├── day_test.go
    │   ├── month.go
    │   ├── month_enumer.go
    │   ├── timerange.go
    │   ├── timerange_test.go
    │   ├── zone.go
    │   └── zone_test.go
    ├── fixed_test.go
    ├── groupe-e.go
    ├── gruenstromindex.go
    ├── helper.go
    ├── helper_test.go
    ├── ngeso.go
    ├── ngeso
    │   └── api.go
    ├── octopus.go
    ├── octopus
    │   ├── graphql
    │   │   ├── api.go
    │   │   ├── api_test.go
    │   │   ├── errors.go
    │   │   └── types.go
    │   └── rest
    │   │   └── api.go
    ├── octopus_test.go
    ├── ostrom.go
    ├── ostrom
    │   └── api.go
    ├── proxy.go
    ├── proxy_average.go
    ├── proxy_average_test.go
    ├── proxy_cache.go
    ├── proxy_cache_error.go
    ├── proxy_cache_helper.go
    ├── pun.go
    ├── slots.go
    ├── slots_test.go
    ├── smartenergy.go
    ├── smartenergy
    │   └── types.go
    ├── solcast.go
    ├── solcast
    │   └── types.go
    ├── stekker.go
    ├── tariff.go
    ├── tariffs.go
    ├── template.go
    ├── template_test.go
    ├── tibber.go
    ├── types.go
    ├── types_test.go
    └── wrapper.go
├── templates
    ├── README.md
    ├── definition
    │   ├── charger
    │   │   ├── abb.yaml
    │   │   ├── abl-em4.yaml
    │   │   ├── abl.yaml
    │   │   ├── ac-elwa-2.yaml
    │   │   ├── ac-elwa-e.yaml
    │   │   ├── ac-thor.yaml
    │   │   ├── alfen.yaml
    │   │   ├── alphatec.yaml
    │   │   ├── alpitronic.yaml
    │   │   ├── amperfied-solar.yaml
    │   │   ├── amperfied.yaml
    │   │   ├── bender-cc.yaml
    │   │   ├── bender-icc.yaml
    │   │   ├── cfos.yaml
    │   │   ├── compleo-duo.yaml
    │   │   ├── compleo-solo.yaml
    │   │   ├── dadapower.yaml
    │   │   ├── daheimladen-pro.yaml
    │   │   ├── daheimladen.yaml
    │   │   ├── daikin-homehub-air2air.yaml
    │   │   ├── daikin-homehub.yaml
    │   │   ├── delta.yaml
    │   │   ├── demo-charger.yaml
    │   │   ├── demo-heatpump.yaml
    │   │   ├── easee.yaml
    │   │   ├── eebus.yaml
    │   │   ├── elli-2.yaml
    │   │   ├── elli-charger-connect.yaml
    │   │   ├── elli-charger-pro.yaml
    │   │   ├── em2go-duo.yaml
    │   │   ├── em2go-home.yaml
    │   │   ├── em2go.yaml
    │   │   ├── emsesp.yaml
    │   │   ├── eprowallbox.yaml
    │   │   ├── etrel-duo.yaml
    │   │   ├── etrel.yaml
    │   │   ├── evbox-livo.yaml
    │   │   ├── evecube.yaml
    │   │   ├── evse-din.yaml
    │   │   ├── evsewifi.yaml
    │   │   ├── fritzdect.yaml
    │   │   ├── fronius-wattpilot.yaml
    │   │   ├── ghost.yaml
    │   │   ├── go-e-v3.yaml
    │   │   ├── go-e.yaml
    │   │   ├── hardybarth-ecb1.yaml
    │   │   ├── hardybarth-salia.yaml
    │   │   ├── heidelberg.yaml
    │   │   ├── hesotec.yaml
    │   │   ├── homeassistant-switch.yaml
    │   │   ├── homematic.yaml
    │   │   ├── homewizard.yaml
    │   │   ├── icharge-cion.yaml
    │   │   ├── idm.yaml
    │   │   ├── innogy-ebox.yaml
    │   │   ├── kathrein.yaml
    │   │   ├── keba-modbus-p40.yaml
    │   │   ├── keba-modbus.yaml
    │   │   ├── keba-udp.yaml
    │   │   ├── kermi.yaml
    │   │   ├── kse.yaml
    │   │   ├── lambda-zewotherm.yaml
    │   │   ├── lg-therma.yaml
    │   │   ├── luxtronik.yaml
    │   │   ├── mennekes-compact.yaml
    │   │   ├── mennekes-hcc3.yaml
    │   │   ├── mystrom.yaml
    │   │   ├── neoom-n-plus.yaml
    │   │   ├── neoom-n.yaml
    │   │   ├── nrggen2.yaml
    │   │   ├── nrgkick-bluetooth.yaml
    │   │   ├── nrgkick-connect.yaml
    │   │   ├── obo.yaml
    │   │   ├── ochsner-bwwp.yaml
    │   │   ├── ocpp-abb-tac.yaml
    │   │   ├── ocpp-abl.yaml
    │   │   ├── ocpp-alfen.yaml
    │   │   ├── ocpp-autel.yaml
    │   │   ├── ocpp-autoaid.yaml
    │   │   ├── ocpp-beny.yaml
    │   │   ├── ocpp-chargeamps.yaml
    │   │   ├── ocpp-elecq.yaml
    │   │   ├── ocpp-enercab.yaml
    │   │   ├── ocpp-enplus.yaml
    │   │   ├── ocpp-entratek.yaml
    │   │   ├── ocpp-esolutions.yaml
    │   │   ├── ocpp-evbox-elvi.yaml
    │   │   ├── ocpp-goe.yaml
    │   │   ├── ocpp-homecharge.yaml
    │   │   ├── ocpp-huawei.yaml
    │   │   ├── ocpp-mennekes-acu.yaml
    │   │   ├── ocpp-orbis.yaml
    │   │   ├── ocpp-sungrow.yaml
    │   │   ├── ocpp-wallbox-fw5.yaml
    │   │   ├── ocpp-wallbox.yaml
    │   │   ├── ocpp-zaptec.yaml
    │   │   ├── ocpp.yaml
    │   │   ├── openevse.yaml
    │   │   ├── openwb-2.0.yaml
    │   │   ├── openwb-pro.yaml
    │   │   ├── openwb.yaml
    │   │   ├── pantabox.yaml
    │   │   ├── pcelectric-garo.yaml
    │   │   ├── peblar.yaml
    │   │   ├── phoenix-charx.yaml
    │   │   ├── phoenix-em-eth.yaml
    │   │   ├── phoenix-ev-eth.yaml
    │   │   ├── phoenix-ev-ser.yaml
    │   │   ├── plugchoice.yaml
    │   │   ├── porsche-pmcc.yaml
    │   │   ├── porsche-pmcp.yaml
    │   │   ├── porsche-wallbox.yaml
    │   │   ├── pracht-alpha.yaml
    │   │   ├── pulsares.yaml
    │   │   ├── pulsatrix.yaml
    │   │   ├── scheider-evlink-v3.yaml
    │   │   ├── semp-sma.yaml
    │   │   ├── semp.yaml
    │   │   ├── senec-plus.yaml
    │   │   ├── senec-premium.yaml
    │   │   ├── shelly.yaml
    │   │   ├── sigenergy.yaml
    │   │   ├── smaevcharger.yaml
    │   │   ├── smartevse.yaml
    │   │   ├── smartwb.yaml
    │   │   ├── solax-g2.yaml
    │   │   ├── solax.yaml
    │   │   ├── stiebel-lwa.yaml
    │   │   ├── stiebel-wpm.yaml
    │   │   ├── sungrow.yaml
    │   │   ├── tapo.yaml
    │   │   ├── tasmota.yaml
    │   │   ├── tessie.yaml
    │   │   ├── tinkerforge-warp.yaml
    │   │   ├── tinkerforge-warp3-smart.yaml
    │   │   ├── tinkerforge-warp3.yaml
    │   │   ├── tplink.yaml
    │   │   ├── twc3.yaml
    │   │   ├── v2c.yaml
    │   │   ├── vaillant.yaml
    │   │   ├── vehicle-api.yaml
    │   │   ├── versicharge.yaml
    │   │   ├── vestel.yaml
    │   │   ├── victron-evcs.yaml
    │   │   ├── victron.yaml
    │   │   ├── viessmann.yaml
    │   │   ├── volttime.yaml
    │   │   ├── wallbe-meter.yaml
    │   │   ├── wallbe-pre2019-meter.yaml
    │   │   ├── wallbe-pre2019.yaml
    │   │   ├── wallbe.yaml
    │   │   ├── webasto-next.yaml
    │   │   ├── weidmüller.yaml
    │   │   ├── weishaupt-wpm.yaml
    │   │   └── zaptec.yaml
    │   ├── common-schema.json
    │   ├── defaults-schema.json
    │   ├── devices-schema.json
    │   ├── embed.go
    │   ├── meter
    │   │   ├── abb-ab.yaml
    │   │   ├── ac-elwa-2.yaml
    │   │   ├── ac-elwa-e.yaml
    │   │   ├── acrel-adw300.yaml
    │   │   ├── alpha-ess-smile.yaml
    │   │   ├── apsystems-ez1.yaml
    │   │   ├── batterx.yaml
    │   │   ├── be-mpm3pm.yaml
    │   │   ├── bgetech-ds100.yaml
    │   │   ├── bgetech-ws100.yaml
    │   │   ├── bosch-bpt.yaml
    │   │   ├── cfos.yaml
    │   │   ├── cg-em24.yaml
    │   │   ├── cg-em24_e1.yaml
    │   │   ├── cg-emt1xx.yaml
    │   │   ├── cg-emt3xx.yaml
    │   │   ├── cozify.yaml
    │   │   ├── demo-battery.yaml
    │   │   ├── demo-meter.yaml
    │   │   ├── deye-hybrid-3p.yaml
    │   │   ├── deye-hybrid-hp3.yaml
    │   │   ├── deye-mi.yaml
    │   │   ├── deye-storage.yaml
    │   │   ├── deye-string.yaml
    │   │   ├── discovergy.yaml
    │   │   ├── dsmr.yaml
    │   │   ├── dsmrlogger-aandewiel.yaml
    │   │   ├── dzg.yaml
    │   │   ├── e3dc-modbus.yaml
    │   │   ├── e3dc-rscp.yaml
    │   │   ├── eastron-sdm120.yaml
    │   │   ├── eastron-sdm220_230.yaml
    │   │   ├── eastron-sdm72.yaml
    │   │   ├── eastron-sdm72v2_630.yaml
    │   │   ├── eebus-mcp.yaml
    │   │   ├── eebus-mgcp.yaml
    │   │   ├── enphase.yaml
    │   │   ├── esphome-dlms-austria.yaml
    │   │   ├── fox-ess-avocado.yaml
    │   │   ├── fox-ess-h1.yaml
    │   │   ├── fox-ess-h3-smart.yaml
    │   │   ├── fox-ess-h3.yaml
    │   │   ├── fritzdect.yaml
    │   │   ├── fritzgrid.yaml
    │   │   ├── fronius-gen24.yaml
    │   │   ├── fronius-ohmpilot.yaml
    │   │   ├── fronius-solarapi-v1.yaml
    │   │   ├── fronius-vertoplus.yaml
    │   │   ├── go-e-controller.yaml
    │   │   ├── goodwe-dt.yaml
    │   │   ├── goodwe-hybrid.yaml
    │   │   ├── goodwe-wifi.yaml
    │   │   ├── growatt-hybrid-tlxh.yaml
    │   │   ├── growatt-hybrid.yaml
    │   │   ├── hager-flow-modbus.yaml
    │   │   ├── homeassistant.yaml
    │   │   ├── homematic.yaml
    │   │   ├── homewizard-kwh.yaml
    │   │   ├── homewizard-p1.yaml
    │   │   ├── hoymiles-ahoydtu.yaml
    │   │   ├── hoymiles-dtugateway.yaml
    │   │   ├── hoymiles-opendtu.yaml
    │   │   ├── huawei-emma.yaml
    │   │   ├── huawei-smartlogger.yaml
    │   │   ├── huawei-sun2000-dongle.yaml
    │   │   ├── huawei-sun2000.yaml
    │   │   ├── iammeter.yaml
    │   │   ├── inepro.yaml
    │   │   ├── iometer.yaml
    │   │   ├── janitza.yaml
    │   │   ├── keba-kecontact.yaml
    │   │   ├── kostal-ksem-inverter.yaml
    │   │   ├── kostal-ksem.yaml
    │   │   ├── kostal-piko-hybrid.yaml
    │   │   ├── kostal-piko-legacy.yaml
    │   │   ├── kostal-piko-mp-plus.yaml
    │   │   ├── kostal-piko-pv.yaml
    │   │   ├── kostal-plenticore-gen2.yaml
    │   │   ├── kostal-plenticore.yaml
    │   │   ├── lg-ess-home-15.yaml
    │   │   ├── lg-ess-home-8-10.yaml
    │   │   ├── loxone.yaml
    │   │   ├── marstek-jupiterc-plus.yaml
    │   │   ├── marstek-venus.yaml
    │   │   ├── mtec-eb-gen2.yaml
    │   │   ├── mtec-eb-gen3.yaml
    │   │   ├── mypv-wifi-meter.yaml
    │   │   ├── mystrom.yaml
    │   │   ├── openems.yaml
    │   │   ├── orno.yaml
    │   │   ├── p1monitor.yaml
    │   │   ├── plexlog.yaml
    │   │   ├── powerdog.yaml
    │   │   ├── powerfox-poweropti.yaml
    │   │   ├── qcells-hybrid-cloud.yaml
    │   │   ├── rct-power.yaml
    │   │   ├── saj-h1.yaml
    │   │   ├── saj-h2.yaml
    │   │   ├── saj-r5.yaml
    │   │   ├── sax.yaml
    │   │   ├── sbc-axx3.yaml
    │   │   ├── schneider-iem3000.yaml
    │   │   ├── senec-home.yaml
    │   │   ├── senergy.yaml
    │   │   ├── shelly-1pm.yaml
    │   │   ├── shelly-3em.yaml
    │   │   ├── shelly-pro-3em.yaml
    │   │   ├── siemens-7kt1665.yaml
    │   │   ├── siemens-junelight.yaml
    │   │   ├── siemens-pac2200.yaml
    │   │   ├── sigenergy.yaml
    │   │   ├── slimmelezer-luxembourg.yaml
    │   │   ├── slimmelezer-v2.yaml
    │   │   ├── slimmelezer.yaml
    │   │   ├── sma-datamanager.yaml
    │   │   ├── sma-energymeter.yaml
    │   │   ├── sma-homemanager.yaml
    │   │   ├── sma-hybrid.yaml
    │   │   ├── sma-inverter-modbus.yaml
    │   │   ├── sma-inverter-speedwire.yaml
    │   │   ├── sma-sbs-15-25-modbus.yaml
    │   │   ├── sma-sbs-modbus.yaml
    │   │   ├── sma-si-modbus.yaml
    │   │   ├── sma-webbox.yaml
    │   │   ├── smartfox-em2.yaml
    │   │   ├── smartfox.yaml
    │   │   ├── sofarsolar-g3.yaml
    │   │   ├── sofarsolar.yaml
    │   │   ├── solaranzeige-mqtt.yaml
    │   │   ├── solaredge-hybrid.yaml
    │   │   ├── solaredge-inverter.yaml
    │   │   ├── solarlog.yaml
    │   │   ├── solarman.yaml
    │   │   ├── solarmax-inverter-smt.yaml
    │   │   ├── solarmax-maxstorage.yaml
    │   │   ├── solarwatt-flex.yaml
    │   │   ├── solarwatt-myreserve-matrix.yaml
    │   │   ├── solarwatt.yaml
    │   │   ├── solax-hybrid-cloud.yaml
    │   │   ├── solax-inverter-cloud.yaml
    │   │   ├── solax.yaml
    │   │   ├── solis-hybrid-s.yaml
    │   │   ├── solis-hybrid.yaml
    │   │   ├── solis.yaml
    │   │   ├── sonnenbatterie.yaml
    │   │   ├── sonnenbatterie_eco56.yaml
    │   │   ├── storaxe.yaml
    │   │   ├── sungrow-hybrid.yaml
    │   │   ├── sungrow-ihm.yaml
    │   │   ├── sungrow-inverter.yaml
    │   │   ├── sunspec-battery-control.yaml
    │   │   ├── sunspec-hybrid.yaml
    │   │   ├── sunspec-inverter-control.yaml
    │   │   ├── sunspec-inverter.yaml
    │   │   ├── sunspec-meter.yaml
    │   │   ├── tapo.yaml
    │   │   ├── tasmota-3p.yaml
    │   │   ├── tasmota-sml.yaml
    │   │   ├── tasmota.yaml
    │   │   ├── tesla-powerwall.yaml
    │   │   ├── thor.yaml
    │   │   ├── tibber-pulse.yaml
    │   │   ├── tplink.yaml
    │   │   ├── tq-em.yaml
    │   │   ├── tq-em420.yaml
    │   │   ├── varta.yaml
    │   │   ├── victron-energy.yaml
    │   │   ├── volkszaehler-http.yaml
    │   │   ├── volkszaehler-importexport.yaml
    │   │   ├── volkszaehler-ws.yaml
    │   │   ├── vzlogger.yaml
    │   │   ├── wago-879-30xx.yaml
    │   │   ├── wattsonic-gen3.yaml
    │   │   ├── wattsonic.yaml
    │   │   ├── youless.yaml
    │   │   └── zendure.yaml
    │   ├── tariff
    │   │   ├── allinpower.yaml
    │   │   ├── amber.yaml
    │   │   ├── api-akkudoktor-de.yaml
    │   │   ├── awattar.yaml
    │   │   ├── demo-co2-forecast.yaml
    │   │   ├── demo-dynamic-grid.yaml
    │   │   ├── demo-solar-forecast.yaml
    │   │   ├── electricitymaps-free.yaml
    │   │   ├── electricitymaps.yaml
    │   │   ├── elering.yaml
    │   │   ├── energinet-co2.yaml
    │   │   ├── energinet-price.yaml
    │   │   ├── energinet.yaml
    │   │   ├── energy-charts-api.yaml
    │   │   ├── energyforecast.yaml
    │   │   ├── enever.yaml
    │   │   ├── entsoe.yaml
    │   │   ├── ews.yaml
    │   │   ├── forecast-solar.yaml
    │   │   ├── green-grid-compass.yaml
    │   │   ├── groupe-e.yaml
    │   │   ├── gruenstromindex.yaml
    │   │   ├── ned.yaml
    │   │   ├── ngeso.yaml
    │   │   ├── nordpool.yaml
    │   │   ├── octopus-api.yaml
    │   │   ├── octopus-productcode.yaml
    │   │   ├── open-meteo.yaml
    │   │   ├── ostrom.yaml
    │   │   ├── pun.yaml
    │   │   ├── smartenergy.yaml
    │   │   ├── solarprognose.yaml
    │   │   ├── solcast.yaml
    │   │   ├── spottyenergy.yaml
    │   │   ├── stekker.yaml
    │   │   ├── tibber.yaml
    │   │   └── victron.yaml
    │   └── vehicle
    │   │   ├── aiways.yaml
    │   │   ├── audi.yaml
    │   │   ├── bmw.yaml
    │   │   ├── cardata.yaml
    │   │   ├── carwings.yaml
    │   │   ├── citroen.yaml
    │   │   ├── dacia.yaml
    │   │   ├── ds.yaml
    │   │   ├── evnotify.yaml
    │   │   ├── fiat.yaml
    │   │   ├── flobz.yaml
    │   │   ├── ford-connect.yaml
    │   │   ├── ford.yaml
    │   │   ├── homeassistant.yaml
    │   │   ├── hyundai.yaml
    │   │   ├── ioBroker.bmw.yaml
    │   │   ├── iso15118.yaml
    │   │   ├── jaguar-landrover.yaml
    │   │   ├── kia.yaml
    │   │   ├── mazda2mqtt.yaml
    │   │   ├── mercedes.yaml
    │   │   ├── mg.yaml
    │   │   ├── mg2mqtt.yaml
    │   │   ├── mini.yaml
    │   │   ├── mz2mqtt.yaml
    │   │   ├── nissan-ariya.yaml
    │   │   ├── nissan.yaml
    │   │   ├── niu-e-scooter.yaml
    │   │   ├── offline.yaml
    │   │   ├── opel.yaml
    │   │   ├── ovms.yaml
    │   │   ├── peugeot.yaml
    │   │   ├── polestar.yaml
    │   │   ├── porsche.yaml
    │   │   ├── renault.yaml
    │   │   ├── seat-cupra.yaml
    │   │   ├── seat.yaml
    │   │   ├── skoda.yaml
    │   │   ├── smart-hello.yaml
    │   │   ├── smart.yaml
    │   │   ├── tesla-ble.yaml
    │   │   ├── tesla.yaml
    │   │   ├── teslafi.yaml
    │   │   ├── teslalogger.yaml
    │   │   ├── teslamate.yaml
    │   │   ├── tessie.yaml
    │   │   ├── toyota.yaml
    │   │   ├── tronity.yaml
    │   │   ├── volvo-connected.yaml
    │   │   ├── volvo2mqtt.yaml
    │   │   ├── vw.yaml
    │   │   └── zero.yaml
    └── evcc.io
    │   └── .gitignore
├── tests
    ├── auth.spec.ts
    ├── backup-restore.spec.ts
    ├── basics.evcc.yaml
    ├── basics.spec.ts
    ├── battery-settings-co2.evcc.yaml
    ├── battery-settings-co2.spec.ts
    ├── battery-settings.evcc.yaml
    ├── battery-settings.spec.ts
    ├── boot.spec.ts
    ├── config-aux.spec.ts
    ├── config-battery.spec.ts
    ├── config-circuit.evcc.yaml
    ├── config-circuit.spec.ts
    ├── config-empty.evcc.yaml
    ├── config-ext-meter.spec.ts
    ├── config-fatals.spec.ts
    ├── config-grid-only.evcc.yaml
    ├── config-grid.spec.ts
    ├── config-invalid-template.spec.ts
    ├── config-invalid-template.sql
    ├── config-loadpoint.spec.ts
    ├── config-messaging.spec.ts
    ├── config-modbus-fields.spec.ts
    ├── config-modbus-fields.sql
    ├── config-mqtt.spec.ts
    ├── config-onboarding.spec.ts
    ├── config-one-lp.evcc.yaml
    ├── config-pv.spec.ts
    ├── config-shm.spec.ts
    ├── config-tariffs.spec.ts
    ├── config-vehicles.spec.ts
    ├── config-with-tariffs.evcc.yaml
    ├── config-with-vehicle.evcc.yaml
    ├── config.spec.ts
    ├── currents.spec.ts
    ├── custom-css.css
    ├── custom-css.spec.ts
    ├── demo.spec.ts
    ├── evcc.ts
    ├── fast.evcc.yaml
    ├── fatal-db.evcc.yaml
    ├── fatal-syntax.evcc.yaml
    ├── fatal.spec.ts
    ├── heating.evcc.yaml
    ├── heating.spec.ts
    ├── hems.spec.ts
    ├── issue.evcc.yaml
    ├── issue.spec.ts
    ├── limits.spec.ts
    ├── loadpoint-sort.evcc.yaml
    ├── loadpoint-sort.spec.ts
    ├── logs.spec.ts
    ├── modals.spec.ts
    ├── mqtt.ts
    ├── password.sql
    ├── plan-fixed-tariff.evcc.yaml
    ├── plan.evcc.yaml
    ├── plan.spec.ts
    ├── sessions.evcc.yaml
    ├── sessions.spec.ts
    ├── sessions.sql
    ├── simulator.evcc.yaml
    ├── simulator.ts
    ├── simulator
    │   ├── api.ts
    │   ├── index.html
    │   ├── src
    │   │   ├── Simulator.vue
    │   │   └── main.ts
    │   └── vite.config.ts
    ├── smart-cost-only.evcc.yaml
    ├── smart-cost-only.spec.ts
    ├── smart-cost.spec.ts
    ├── smart-feedin.evcc.yaml
    ├── smart-feedin.spec.ts
    ├── sponsor.evcc.yaml
    ├── sponsor.spec.ts
    ├── sponsor.sql
    ├── statistics.evcc.yaml
    ├── statistics.spec.ts
    ├── statistics.sql
    ├── utils.ts
    ├── vehicle-error.evcc.yaml
    ├── vehicle-error.spec.ts
    ├── vehicle-settings.spec.ts
    └── ws.spec.ts
├── tsconfig.json
├── util
    ├── auth
    │   ├── auth.go
    │   └── auth_test.go
    ├── cache.go
    ├── cache_test.go
    ├── cloud
    │   ├── api.go
    │   └── client.go
    ├── config
    │   ├── config.go
    │   ├── device.go
    │   ├── handler.go
    │   ├── instance.go
    │   └── types.go
    ├── config_redactor.go
    ├── decoder.go
    ├── decoder_test.go
    ├── duration.go
    ├── encode
    │   ├── encode.go
    │   └── encode_test.go
    ├── env.go
    ├── format.go
    ├── format_functions.go
    ├── format_test.go
    ├── homeassistant
    │   └── connection.go
    ├── jq
    │   └── jq.go
    ├── locale
    │   ├── internal
    │   │   └── types.go
    │   ├── locale.go
    │   └── locale_test.go
    ├── log.go
    ├── log_context.go
    ├── log_redactor.go
    ├── log_test.go
    ├── logstash
    │   ├── element.go
    │   ├── levels.go
    │   ├── log.go
    │   └── log_test.go
    ├── machine
    │   ├── machine.go
    │   └── machine_test.go
    ├── metering.go
    ├── modbus
    │   ├── connection.go
    │   ├── functions.go
    │   ├── log.go
    │   ├── modbus.go
    │   ├── modbus_test.go
    │   ├── mutex.go
    │   ├── register.go
    │   ├── register_test.go
    │   └── sunspec.go
    ├── monitor.go
    ├── monitor_test.go
    ├── net.go
    ├── net_test.go
    ├── oauth
    │   ├── helper.go
    │   ├── tokensource.go
    │   └── tokensource_test.go
    ├── param.go
    ├── param_shard.go
    ├── param_test.go
    ├── pipe
    │   ├── limiter.go
    │   └── limiter_test.go
    ├── queue.go
    ├── registry
    │   └── registry.go
    ├── request
    │   ├── functions.go
    │   ├── helper.go
    │   ├── json.go
    │   ├── redirect.go
    │   ├── roundtrip.go
    │   └── xml.go
    ├── shortrfc3339
    │   ├── shortrfc3339.go
    │   └── shortrfc3339_test.go
    ├── sponsor
    │   ├── auth.go
    │   ├── pulsares.go
    │   └── victron.go
    ├── tee.go
    ├── telemetry
    │   ├── charge.go
    │   └── types.go
    ├── templates
    │   ├── class.go
    │   ├── class_enumer.go
    │   ├── defaults.go
    │   ├── defaults.yaml
    │   ├── documentation.go
    │   ├── documentation.tpl
    │   ├── documentation_modbus.tpl
    │   ├── generate
    │   │   └── main.go
    │   ├── includes
    │   │   ├── eebus.tpl
    │   │   ├── mqtt.tpl
    │   │   ├── ocpp.tpl
    │   │   ├── switchsocket.tpl
    │   │   ├── tariff-base.tpl
    │   │   ├── tariff-features.tpl
    │   │   ├── vehicle-base.tpl
    │   │   ├── vehicle-common.tpl
    │   │   ├── vehicle-features.tpl
    │   │   └── vehicle-language.tpl
    │   ├── init.go
    │   ├── merge.go
    │   ├── merge_test.go
    │   ├── modbus.tpl
    │   ├── paramtype.go
    │   ├── paramtype_enumer.go
    │   ├── proxy.tpl
    │   ├── render_instance.go
    │   ├── render_testing.go
    │   ├── template.go
    │   ├── template_modbus.go
    │   ├── template_test.go
    │   ├── types.go
    │   ├── usage.go
    │   ├── usage_enumer.go
    │   ├── utils.go
    │   └── utils_test.go
    ├── test
    │   ├── ci.go
    │   └── errors.go
    ├── time.go
    ├── token.go
    ├── transport
    │   ├── basicauth.go
    │   ├── bearer.go
    │   ├── decorator.go
    │   ├── decorators.go
    │   └── default.go
    ├── urlvalues
    │   └── url.go
    └── version.go
├── vehicle
    ├── aiways.go
    ├── aiways
    │   ├── api.go
    │   ├── identity.go
    │   ├── provider.go
    │   └── types.go
    ├── audi.go
    ├── audi
    │   ├── etron
    │   │   ├── api.go
    │   │   ├── params.go
    │   │   └── types.go
    │   ├── params.go
    │   └── samples
    │   │   └── status.json
    ├── bluelink.go
    ├── bluelink
    │   ├── api.go
    │   ├── identity.go
    │   ├── provider.go
    │   └── types.go
    ├── bmw
    │   ├── cardata
    │   │   ├── api.go
    │   │   ├── mqtt.go
    │   │   ├── provider.go
    │   │   ├── provider_test.go
    │   │   ├── token.go
    │   │   └── types.go
    │   └── connected
    │   │   ├── api.go
    │   │   ├── identity.go
    │   │   ├── param.go
    │   │   ├── provider.go
    │   │   └── types.go
    ├── bmw_deprecated.go
    ├── cardata.go
    ├── carwings.go
    ├── cloud.go
    ├── config.go
    ├── embed.go
    ├── fiat.go
    ├── fiat
    │   ├── api.go
    │   ├── controller.go
    │   ├── identity.go
    │   ├── provider.go
    │   └── types.go
    ├── ford-connect.go
    ├── ford.go
    ├── ford
    │   ├── api.go
    │   ├── autonomic
    │   │   ├── api.go
    │   │   ├── identity.go
    │   │   └── types.go
    │   ├── connect
    │   │   ├── api.go
    │   │   ├── identity.go
    │   │   ├── provider.go
    │   │   └── types.go
    │   ├── identity.go
    │   ├── provider.go
    │   └── types.go
    ├── helper.go
    ├── homeassistant.go
    ├── jlr.go
    ├── jlr
    │   ├── api.go
    │   ├── identity.go
    │   ├── provider.go
    │   └── types.go
    ├── mb
    │   └── identity.go
    ├── mercedes.go
    ├── mercedes
    │   ├── api.go
    │   ├── helper.go
    │   ├── identity.go
    │   ├── pb
    │   │   ├── acp.pb.go
    │   │   ├── client.pb.go
    │   │   ├── cluster.pb.go
    │   │   ├── eventpush.pb.go
    │   │   ├── protos
    │   │   │   └── protos.pb.go
    │   │   ├── service-activation.pb.go
    │   │   ├── user-events.pb.go
    │   │   ├── vehicle-commands.pb.go
    │   │   ├── vehicle-events.pb.go
    │   │   ├── vehicleapi.pb.go
    │   │   └── vin-events.pb.go
    │   ├── provider.go
    │   └── types.go
    ├── mg.go
    ├── nissan.go
    ├── nissan
    │   ├── api.go
    │   ├── identity.go
    │   ├── provider.go
    │   └── types.go
    ├── niu.go
    ├── niu
    │   ├── types.go
    │   └── types_test.go
    ├── ovms.go
    ├── ovms
    │   └── types.go
    ├── polestar.go
    ├── polestar
    │   ├── api.go
    │   ├── identity.go
    │   ├── provider.go
    │   ├── query.gql
    │   └── types.go
    ├── porsche.go
    ├── porsche
    │   ├── api.go
    │   ├── api_emobility.go
    │   ├── identity.go
    │   ├── provider.go
    │   └── types.go
    ├── psa.go
    ├── psa
    │   ├── api.go
    │   ├── duration.go
    │   ├── helper.go
    │   ├── identity.go
    │   ├── oauth2.go
    │   ├── provider.go
    │   └── types.go
    ├── renault.go
    ├── renault
    │   ├── gigya
    │   │   └── identity.go
    │   ├── kamereon
    │   │   ├── api.go
    │   │   └── types.go
    │   ├── keys
    │   │   └── keys.go
    │   └── provider.go
    ├── saic
    │   ├── api.go
    │   ├── identity.go
    │   ├── provider.go
    │   └── requests
    │   │   ├── api_config.go
    │   │   ├── basic_encryption.go
    │   │   ├── encryption.go
    │   │   ├── hashUtils.go
    │   │   ├── macUtils.go
    │   │   ├── sendRequest.go
    │   │   └── types.go
    ├── seat-cupra.go
    ├── seat.go
    ├── seat
    │   ├── api.go
    │   ├── cupra
    │   │   ├── api.go
    │   │   ├── params.go
    │   │   ├── provider.go
    │   │   └── types.go
    │   └── params.go
    ├── skoda.go
    ├── skoda
    │   ├── api.go
    │   ├── params.go
    │   ├── provider.go
    │   ├── service
    │   │   └── tokenrefreshservice.go
    │   ├── tokenrefreshservice
    │   │   └── endpoint.go
    │   └── types.go
    ├── smart-hello.go
    ├── smart
    │   ├── api.go
    │   ├── hello
    │   │   ├── api.go
    │   │   ├── const.go
    │   │   ├── helper.go
    │   │   ├── identity.go
    │   │   ├── provider.go
    │   │   ├── types.go
    │   │   └── types_test.go
    │   ├── provider.go
    │   └── types.go
    ├── template.go
    ├── template_test.go
    ├── tesla.go
    ├── tesla
    │   ├── api_test.go
    │   ├── controller.go
    │   ├── helper.go
    │   ├── helper_test.go
    │   ├── identity.go
    │   ├── provider.go
    │   └── types.go
    ├── toyota.go
    ├── toyota
    │   ├── api.go
    │   ├── api_test.go
    │   ├── identity.go
    │   ├── identity_test.go
    │   ├── provider.go
    │   └── types.go
    ├── tronity.go
    ├── tronity
    │   ├── auth.go
    │   └── types.go
    ├── tronity_decorators.go
    ├── types.go
    ├── vag
    │   ├── aazsproxy
    │   │   └── endpoint.go
    │   ├── cariad
    │   │   └── const.go
    │   ├── challenge.go
    │   ├── idkproxy
    │   │   └── endpoint.go
    │   ├── loginapps
    │   │   ├── endpoint.go
    │   │   ├── token.go
    │   │   └── token_test.go
    │   ├── mbb
    │   │   └── endpoint.go
    │   ├── service
    │   │   ├── azs.go
    │   │   └── mbb.go
    │   ├── token.go
    │   ├── token_test.go
    │   ├── tokensource.go
    │   ├── tokensource_test.go
    │   └── vwidentity
    │   │   ├── endpoint.go
    │   │   ├── forms.go
    │   │   ├── forms_test.go
    │   │   └── oauth2.go
    ├── vehicle.go
    ├── vehicle_decorators.go
    ├── volvo-connected.go
    ├── volvo
    │   ├── connected
    │   │   ├── api.go
    │   │   ├── oauth2.go
    │   │   ├── provider.go
    │   │   └── types.go
    │   └── types.go
    ├── vw.go
    ├── vw
    │   ├── api.go
    │   ├── id
    │   │   ├── api.go
    │   │   ├── params.go
    │   │   ├── provider.go
    │   │   └── types.go
    │   ├── params.go
    │   ├── provider.go
    │   ├── samples
    │   │   ├── rolesrights_egolf.json
    │   │   └── rolesrights_q55.json
    │   ├── types.go
    │   ├── types_rolesrights.go
    │   ├── types_status.go
    │   └── types_test.go
    ├── wrapper.go
    ├── zero
    │   ├── api.go
    │   ├── provider.go
    │   └── types.go
    └── zeromotorcycles.go
├── vite.config.ts
└── vitest.config.ts


/.cursorrules:
--------------------------------------------------------------------------------
1 | AGENTS.md


--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
 1 | .cache
 2 | .storybook
 3 | .vscode
 4 | *.conf
 5 | *.Dockerfile
 6 | *.gz
 7 | *.image
 8 | *.json
 9 | *.sh
10 | *.yaml
11 | Dockerfile
12 | evcc
13 | evcc.exe
14 | builddir
15 | node_modules
16 | release
17 | !entrypoint.sh
18 | !evcc.dist.yaml
19 | !package*.json
20 | 


--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
 1 | ; indicate this is the root of the project
 2 | root = true
 3 | 
 4 | [*]
 5 | charset = utf-8
 6 | 
 7 | end_of_line = LF
 8 | insert_final_newline = true
 9 | trim_trailing_whitespace = true
10 | 
11 | indent_style = tab
12 | indent_size = 4
13 | 
14 | [*.css]
15 | indent_size = 2
16 | 
17 | [*.{js,html,yml,yaml,json,md,ts}]
18 | indent_style = space
19 | indent_size = 2
20 | 


--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
 1 | # These are supported funding model platforms
 2 | 
 3 | github: evcc-io
 4 | patreon: # Replace with a single Patreon username
 5 | open_collective: # Replace with a single Open Collective username
 6 | ko_fi: # Replace with a single Ko-fi username
 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
 9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | otechie: # Replace with a single Otechie username
12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
13 | 


--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
2 | contact_links:
3 |   - name: Need help?
4 |     url: https://github.com/evcc-io/evcc/discussions/categories/need-help
5 |     about: GitHub community discussions is a good place to ask questions.
6 | 


--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
 1 | ---
 2 | name: Feature request
 3 | about: Suggest an idea for this project
 4 | title: ''
 5 | labels: ''
 6 | assignees: ''
 7 | 
 8 | ---
 9 | 
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 | 
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 | 
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 | 
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 | 


--------------------------------------------------------------------------------
/.github/copilot-instructions.md:
--------------------------------------------------------------------------------
1 | ../AGENTS.md


--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 |   - package-ecosystem: "github-actions"
4 |     directory: "/"
5 |     schedule:
6 |       interval: "monthly"
7 |     labels:
8 |       - "infrastructure"
9 | 


--------------------------------------------------------------------------------
/.github/issue_label_bot.yaml:
--------------------------------------------------------------------------------
1 | label-alias:
2 |   bug: "bug"
3 |   feature_request: "enhancement"
4 |   question: "question"
5 | 


--------------------------------------------------------------------------------
/.github/workflows/openapi-validate.yml:
--------------------------------------------------------------------------------
 1 | name: openapi-validate
 2 | 
 3 | permissions:
 4 |   contents: read
 5 | 
 6 | on:
 7 |   workflow_dispatch:
 8 |   pull_request:
 9 |     paths:
10 |       - "server/openapi.yaml"
11 |       - ".github/workflows/openapi-validate.yml"
12 | 
13 | jobs:
14 |   validate-openapi:
15 |     name: Validate OpenAPI spec
16 |     runs-on: depot-ubuntu-24.04-arm
17 |     steps:
18 |       - name: Checkout
19 |         uses: actions/checkout@v5
20 |       - name: Setup Go
21 |         uses: actions/setup-go@v6
22 |         with:
23 |           go-version: stable
24 |       - name: Validate OpenAPI spec
25 |         run: go run github.com/getkin/kin-openapi/cmd/validate@v0.133.0 -- server/openapi.yaml
26 | 


--------------------------------------------------------------------------------
/.github/workflows/schema.yml:
--------------------------------------------------------------------------------
 1 | name: Validate Schema
 2 | 
 3 | on:
 4 |   push:
 5 |     paths:
 6 |       - "*.yaml"
 7 |       - "*.json"
 8 |   pull_request:
 9 |     paths:
10 |       - "*.yaml"
11 |       - "*.json"
12 | 
13 | jobs:
14 |   build:
15 |     runs-on: depot-ubuntu-24.04-arm
16 | 
17 |     permissions:
18 |       contents: read
19 | 
20 |     steps:
21 |       - uses: actions/checkout@v5
22 |         with:
23 |           persist-credentials: false
24 |       - uses: nwisbeta/validate-yaml-schema@v2.0.0
25 |         with:
26 |           yamlSchemasJson: |
27 |             {
28 |                 "./schema.json": ["evcc.dist.yaml"]
29 |             }
30 | 


--------------------------------------------------------------------------------
/.github/workflows/stale.yaml:
--------------------------------------------------------------------------------
 1 | name: "Stale issue handler"
 2 | 
 3 | on:
 4 |   workflow_dispatch:
 5 |   schedule:
 6 |     - cron: "0 0 * * *"
 7 |   issue_comment:
 8 |     types: [created]
 9 | 
10 | jobs:
11 |   stale:
12 |     permissions:
13 |       contents: read
14 |       issues: write
15 |       pull-requests: write
16 |     runs-on: depot-ubuntu-24.04-arm
17 |     steps:
18 |       - uses: actions/stale@v10
19 |         id: stale
20 |         with:
21 |           days-before-stale: 7
22 |           days-before-close: 5
23 |           exempt-issue-labels: "pinned,security,backlog,bug"
24 |           exempt-pr-labels: "pinned,security,backlog,bug"
25 | 


--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | tests/custom-css.css


--------------------------------------------------------------------------------
/.storybook/main.ts:
--------------------------------------------------------------------------------
 1 | import { StorybookConfig } from "@storybook/vue3-vite";
 2 | 
 3 | export default {
 4 |   stories: ["../assets/js/**/*.stories.@(js|ts)"],
 5 |   addons: ["@chromatic-com/storybook"],
 6 |   framework: {
 7 |     name: "@storybook/vue3-vite",
 8 |     options: {},
 9 |   },
10 | } satisfies StorybookConfig;
11 | 


--------------------------------------------------------------------------------
/.vscode/extensions.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "recommendations": [
 3 |     "Vue.volar",
 4 |     "vitest.explorer",
 5 |     "golang.go",
 6 |     "esbenp.prettier-vscode",
 7 |     "yoavbls.pretty-ts-errors",
 8 |   ]
 9 | }
10 | 


--------------------------------------------------------------------------------
/LICENSES/exclusions.md:
--------------------------------------------------------------------------------
1 | # MIT License Exclusions
2 | 
3 | Sponsor-required components are **NOT** covered by the MIT License.
4 | 
5 | See file license header for details.
6 | If you want to use them in your own project, one evcc sponsorship token is required per evcc instance.
7 | Custom licensing agreements are available - please [contact us](mailto:info@evcc.io) to discuss your specific requirements.
8 | 


--------------------------------------------------------------------------------
/LICENSES/fonts.md:
--------------------------------------------------------------------------------
1 | # Font Licenses
2 | 
3 | ## Montserrat Font
4 | 
5 | - **Source**: https://github.com/JulietaUla/Montserrat
6 | - **License**: SIL Open Font License 1.1
7 | - **Files**: /assets/font/Montserrat-\*.woff2
8 | 


--------------------------------------------------------------------------------
/LICENSES/icons.md:
--------------------------------------------------------------------------------
 1 | # Icon Licenses
 2 | 
 3 | ## Material Symbols
 4 | 
 5 | - **Source**: https://github.com/google/material-design-icons
 6 | - **License**: Apache License 2.0
 7 | - **Files**: /assets/js/components/MaterialIcon/\*.vue
 8 | - **Notes**: Repackaged as Vue components, some modified/adapted versions
 9 | 
10 | ## H2D2 Shopicons
11 | 
12 | - **Source**: https://github.com/H2D2-Design/h2d2-shopicons
13 | - **License**: Apache License 2.0
14 | - **Usage**: Regular dependency
15 | 


--------------------------------------------------------------------------------
/api/actionconfig_test.go:
--------------------------------------------------------------------------------
 1 | package api
 2 | 
 3 | import (
 4 | 	"testing"
 5 | 
 6 | 	"github.com/stretchr/testify/assert"
 7 | )
 8 | 
 9 | func TestActionConfigString(t *testing.T) {
10 | 	var a ActionConfig
11 | 	assert.NotPanics(t, func() {
12 | 		_ = a.String()
13 | 	})
14 | }
15 | 


--------------------------------------------------------------------------------
/api/batterymode.go:
--------------------------------------------------------------------------------
 1 | package api
 2 | 
 3 | // BatteryMode is the home battery operation mode. Valid values are normal, locked and charge
 4 | type BatteryMode int
 5 | 
 6 | //go:generate go tool enumer -type BatteryMode -trimprefix Battery -transform=lower
 7 | const (
 8 | 	BatteryUnknown BatteryMode = iota
 9 | 	BatteryNormal
10 | 	BatteryHold
11 | 	BatteryCharge
12 | )
13 | 


--------------------------------------------------------------------------------
/api/feature.go:
--------------------------------------------------------------------------------
 1 | package api
 2 | 
 3 | type Feature int
 4 | 
 5 | //go:generate go tool enumer -type Feature -text
 6 | const (
 7 | 	_                Feature = iota
 8 | 	CoarseCurrent            // charger
 9 | 	IntegratedDevice         // charger
10 | 	Heating                  // charger
11 | 	Average                  // tariff
12 | 	Cacheable                // tariff
13 | 	Offline                  // vehicle
14 | 	Retryable                // vehicle
15 | 	Streaming                // vehicle
16 | 	WelcomeCharge            // vehicle
17 | )
18 | 


--------------------------------------------------------------------------------
/api/marshal.go:
--------------------------------------------------------------------------------
 1 | package api
 2 | 
 3 | // BytesMarshaler marshals into bytes/string representation
 4 | type BytesMarshaler interface {
 5 | 	MarshalBytes() ([]byte, error)
 6 | }
 7 | 
 8 | // StructMarshaler marshals into a struct representation
 9 | type StructMarshaler interface {
10 | 	MarshalStruct() (any, error)
11 | }
12 | 


--------------------------------------------------------------------------------
/api/plans.go:
--------------------------------------------------------------------------------
 1 | package api
 2 | 
 3 | type RepeatingPlan struct {
 4 | 	Weekdays     []int  `json:"weekdays"`     // 0-6 (Sunday-Saturday)
 5 | 	Time         string `json:"time"`         // HH:MM
 6 | 	Tz           string `json:"tz"`           // timezone in IANA format
 7 | 	Soc          int    `json:"soc"`          // target soc
 8 | 	Precondition int64  `json:"precondition"` // precondition duration in seconds
 9 | 	Active       bool   `json:"active"`       // active flag
10 | }
11 | 


--------------------------------------------------------------------------------
/api/plugin.go:
--------------------------------------------------------------------------------
1 | package api
2 | 
3 | // Custom meter/charger/vehicle type
4 | const Custom = "custom"
5 | 


--------------------------------------------------------------------------------
/api/proto/auth.proto:
--------------------------------------------------------------------------------
 1 | syntax = "proto3";
 2 | 
 3 | // protoc proto/auth.proto --go_out=. --go-grpc_out=.
 4 | 
 5 | import "google/protobuf/timestamp.proto";
 6 | 
 7 | option go_package = "proto/pb";
 8 | 
 9 | service Auth {
10 | 	rpc IsAuthorized (AuthRequest) returns (AuthReply) {}
11 | }
12 | 
13 | message AuthRequest {
14 | 	string token = 1;
15 | }
16 | 
17 | message AuthReply {
18 | 	bool authorized = 1;
19 | 	string subject = 2;
20 | 	google.protobuf.Timestamp expires_at = 3;
21 | }
22 | 


--------------------------------------------------------------------------------
/api/proto/vehicle.proto:
--------------------------------------------------------------------------------
 1 | syntax = "proto3";
 2 | 
 3 | // protoc proto/vehicle.proto --go_out=. --go-grpc_out=.
 4 | 
 5 | option go_package = "proto/pb";
 6 | 
 7 | service Vehicle {
 8 | 	rpc New (NewRequest) returns (NewReply) {}
 9 | 	rpc SoC (SoCRequest) returns (SoCReply) {}
10 | }
11 | 
12 | message NewRequest {
13 | 	string token = 1;
14 | 	string type = 2;
15 | 	map<string,string> config = 3;
16 | }
17 | 
18 | message NewReply {
19 | 	int64 vehicle_id = 1;
20 | }
21 | 
22 | message SoCRequest {
23 | 	string token = 1;
24 | 	int64 vehicle_id = 2;
25 | }
26 | 
27 | message SoCReply {
28 | 	double soc = 1;
29 | }
30 | 


--------------------------------------------------------------------------------
/api/proto/victron.proto:
--------------------------------------------------------------------------------
 1 | syntax = "proto3";
 2 | 
 3 | // protoc proto/victron.proto --go_out=. --go-grpc_out=.
 4 | 
 5 | option go_package = "proto/pb";
 6 | 
 7 | service Victron {
 8 | 	rpc IsValidDevice (VictronRequest) returns (VictronReply) {}
 9 | }
10 | 
11 | message VictronRequest {
12 | 	string productId = 1;
13 | 	string vrmId = 2;
14 | 	string serial = 3;
15 | 	string board = 4;
16 | }
17 | 
18 | message VictronReply {
19 | 	bool authorized = 1;
20 | 	string subject = 2;
21 | }
22 | 


--------------------------------------------------------------------------------
/api/reason.go:
--------------------------------------------------------------------------------
 1 | package api
 2 | 
 3 | type Reason int
 4 | 
 5 | //go:generate go tool enumer -type Reason -trimprefix Reason -transform=lower
 6 | const (
 7 | 	ReasonUnknown Reason = iota
 8 | 	ReasonWaitingForAuthorization
 9 | 	ReasonDisconnectRequired
10 | )
11 | 


--------------------------------------------------------------------------------
/api/store/types.go:
--------------------------------------------------------------------------------
 1 | package store
 2 | 
 3 | // Provider creates a Persister for given string key
 4 | type Provider func(string) Store
 5 | 
 6 | // Store can load and store data
 7 | type Store interface {
 8 | 	Load(any) error
 9 | 	Save(any) error
10 | }
11 | 


--------------------------------------------------------------------------------
/api/tariff.go:
--------------------------------------------------------------------------------
 1 | package api
 2 | 
 3 | //go:generate go tool enumer -type TariffType -trimprefix TariffType -transform=lower -text
 4 | //go:generate go tool enumer -type TariffUsage -trimprefix TariffUsage -transform=lower
 5 | 
 6 | type TariffType int
 7 | 
 8 | const (
 9 | 	_ TariffType = iota
10 | 	TariffTypePriceStatic
11 | 	TariffTypePriceDynamic
12 | 	TariffTypePriceForecast
13 | 	TariffTypeCo2
14 | 	TariffTypeSolar
15 | )
16 | 
17 | type TariffUsage int
18 | 
19 | const (
20 | 	_ TariffUsage = iota
21 | 	TariffUsageCo2
22 | 	TariffUsageFeedIn
23 | 	TariffUsageGrid
24 | 	TariffUsagePlanner
25 | 	TariffUsageSolar
26 | )
27 | 


--------------------------------------------------------------------------------
/assets/font/Montserrat-Bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evcc-io/evcc/2291b371e343043037ebef13c143a8c633eeb853/assets/font/Montserrat-Bold.woff2


--------------------------------------------------------------------------------
/assets/font/Montserrat-Medium.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evcc-io/evcc/2291b371e343043037ebef13c143a8c633eeb853/assets/font/Montserrat-Medium.woff2


--------------------------------------------------------------------------------
/assets/github/evcc-gopher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evcc-io/evcc/2291b371e343043037ebef13c143a8c633eeb853/assets/github/evcc-gopher.png


--------------------------------------------------------------------------------
/assets/github/screenshot.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evcc-io/evcc/2291b371e343043037ebef13c143a8c633eeb853/assets/github/screenshot.webp


--------------------------------------------------------------------------------
/assets/js/components/Config/EebusModal.vue:
--------------------------------------------------------------------------------
 1 | <template>
 2 | 	<YamlModal
 3 | 		id="eebusModal"
 4 | 		:title="$t('config.eebus.title')"
 5 | 		:description="$t('config.eebus.description')"
 6 | 		docs="/docs/reference/configuration/eebus"
 7 | 		:defaultYaml="defaultYaml"
 8 | 		removeKey="eebus"
 9 | 		endpoint="/config/eebus"
10 | 		@changed="$emit('changed')"
11 | 	/>
12 | </template>
13 | 
14 | <script>
15 | import YamlModal from "./YamlModal.vue";
16 | import defaultYaml from "./defaultYaml/eebus.yaml?raw";
17 | 
18 | export default {
19 | 	name: "EebusModal",
20 | 	components: { YamlModal },
21 | 	emits: ["changed"],
22 | 	data() {
23 | 		return { defaultYaml: defaultYaml.trim() };
24 | 	},
25 | };
26 | </script>
27 | 


--------------------------------------------------------------------------------
/assets/js/components/Config/ExperimentalBanner.vue:
--------------------------------------------------------------------------------
 1 | <template>
 2 | 	<div class="alert alert-warning my-4 pb-0" role="alert" data-testid="experimental-banner">
 3 | 		<p>
 4 | 			<strong>Experimental! 🧪</strong>
 5 | 			The UI configuration is still in development. Found an issue? Please
 6 | 			<a href="https://github.com/evcc-io/evcc/issues" target="_blank">report it on GitHub</a
 7 | 			>. Need to reset? Delete <code>evcc.db</code> or run <code>evcc migrate --reset</code>.
 8 | 			Note: Disabling experimental features only hides the UI features. Your configuration
 9 | 			stays untouched.
10 | 		</p>
11 | 	</div>
12 | </template>
13 | 
14 | <script>
15 | export default {
16 | 	name: "ExperimentalBanner",
17 | };
18 | </script>
19 | 


--------------------------------------------------------------------------------
/assets/js/components/Config/HemsModal.vue:
--------------------------------------------------------------------------------
 1 | <template>
 2 | 	<YamlModal
 3 | 		id="hemsModal"
 4 | 		:title="$t('config.hems.title')"
 5 | 		:description="$t('config.hems.description')"
 6 | 		docs="/docs/features/14a-enwg-steuve"
 7 | 		:defaultYaml="defaultYaml"
 8 | 		endpoint="/config/hems"
 9 | 		removeKey="hems"
10 | 		data-testid="hems-modal"
11 | 		@changed="$emit('changed')"
12 | 	/>
13 | </template>
14 | 
15 | <script>
16 | import YamlModal from "./YamlModal.vue";
17 | import defaultYaml from "./defaultYaml/hems.yaml?raw";
18 | 
19 | export default {
20 | 	name: "HemsModal",
21 | 	components: { YamlModal },
22 | 	emits: ["changed"],
23 | 	data() {
24 | 		return { defaultYaml: defaultYaml.trim() };
25 | 	},
26 | };
27 | </script>
28 | 


--------------------------------------------------------------------------------
/assets/js/components/Config/Markdown.vue:
--------------------------------------------------------------------------------
 1 | <template>
 2 | 	<!-- eslint-disable-next-line vue/no-v-html -->
 3 | 	<div class="root" v-html="compiledMarkdown"></div>
 4 | </template>
 5 | 
 6 | <script>
 7 | import snarkdown from "snarkdown";
 8 | 
 9 | export default {
10 | 	name: "MarkdownRenderer",
11 | 	props: {
12 | 		markdown: String,
13 | 	},
14 | 	computed: {
15 | 		compiledMarkdown() {
16 | 			return snarkdown(this.markdown);
17 | 		},
18 | 	},
19 | };
20 | </script>
21 | <style scoped>
22 | .root {
23 | 	max-width: 100%;
24 | }
25 | .root :deep(pre.code) {
26 | 	overflow-x: auto;
27 | 	margin: 1em 0;
28 | 	hyphens: none;
29 | }
30 | </style>
31 | 


--------------------------------------------------------------------------------
/assets/js/components/Config/defaultYaml/eebus.yaml:
--------------------------------------------------------------------------------
 1 | #shipid: EVCC-1234567890abcdef
 2 | #interfaces:
 3 | #  - eth0
 4 | #certificate:
 5 | #  public: |
 6 | #    -----BEGIN CERTIFICATE-----
 7 | #    1234567890abcdef==
 8 | #    -----END CERTIFICATE-----
 9 | #  private: |
10 | #    -----BEGIN EC PRIVATE KEY-----
11 | #    1234567890abcdef
12 | #    -----END EC PRIVATE KEY-----
13 | 


--------------------------------------------------------------------------------
/assets/js/components/Config/defaultYaml/heatpump.yaml:
--------------------------------------------------------------------------------
 1 | ## required attributes [type: heatpump]
 2 | 
 3 | setmaxpower: # update the maximum heating power
 4 |   source: js
 5 |   script: console.log(maxpower); #
 6 | 
 7 | ## optional attributes (read-only)
 8 | 
 9 | #getmaxpower: # heating power in W
10 | #  source: const
11 | #  value: 5000
12 | #power: # heating power in W
13 | #  source: const
14 | #  value: 2000
15 | #energy: # meter reading in kWh
16 | #  source: const
17 | #  value: 42.5
18 | #temp: # current temperature (°C)
19 | #  source: const
20 | #  value: 45.5
21 | #limittemp: # temperature limit (°C) configured in device
22 | #  source: const
23 | #  value: 60
24 | 


--------------------------------------------------------------------------------
/assets/js/components/Config/defaultYaml/hems.yaml:
--------------------------------------------------------------------------------
 1 | ## external control via binary in put
 2 | 
 3 | #type: relay
 4 | #maxPower: 4200 # limit loadpoints to 4.2 kW total
 5 | #limit: # limit signal, plugin
 6 | #  source: mqtt
 7 | #  topic: hems/limit/status # 0/false = normal, 1/true = limit active
 8 | 
 9 | ## external control via EEBus protocol
10 | 
11 | #type: eebus # general EEBus setup (cert gen) required
12 | #ski: "1234-5678-90AB-CDEF" # SKI of control box (grid operator)
13 | 


--------------------------------------------------------------------------------
/assets/js/components/Config/defaultYaml/modbusproxy.yaml:
--------------------------------------------------------------------------------
1 | #- port: 5021 # proxy port for incoming ModbusTCP requests
2 | #  uri: 192.0.2.2:502 # device address for downstream requests
3 | #  rtu: true # optional: use RTU for downstream requests to device
4 | #- port: 5022 # proxy port for incoming ModbusTCP requests
5 | #  device: /dev/ttyUSB0 # local device for downstream requests
6 | #  baudrate: 9600
7 | #  comset: "8N1"
8 | 


--------------------------------------------------------------------------------
/assets/js/components/Config/defaultYaml/tariffs.yaml:
--------------------------------------------------------------------------------
 1 | #currency: EUR
 2 | 
 3 | #grid: # price using energy from the grid
 4 | #  type: fixed
 5 | #  price: 0.294 # EUR/kWh
 6 | 
 7 | #feedin: # price for feeding solar energy to the grid
 8 | #  type: fixed
 9 | #  price: 0.08 # EUR/kWh
10 | 
11 | #co2: # carbon intensity forecast
12 | #  type: template
13 | #  template: grünstromindex
14 | #  zip: <zip>
15 | 
16 | #solar: # list of pv generation forecast (additive)
17 | #- type: template
18 | #  template: solcast
19 | #  site: <site>
20 | #  token: <token>
21 | 


--------------------------------------------------------------------------------
/assets/js/components/Footer/Footer.vue:
--------------------------------------------------------------------------------
 1 | <template>
 2 | 	<footer class="footer" data-testid="footer">
 3 | 		<div class="container py-2">
 4 | 			<div class="d-flex justify-content-between">
 5 | 				<Version v-bind="version" />
 6 | 				<Savings v-bind="savings" />
 7 | 			</div>
 8 | 		</div>
 9 | 	</footer>
10 | </template>
11 | 
12 | <script lang="ts">
13 | import "@h2d2/shopicons/es/filled/testtube";
14 | 
15 | import Version from "./Version.vue";
16 | import Savings from "../Savings/Savings.vue";
17 | import { defineComponent } from "vue";
18 | 
19 | export default defineComponent({
20 | 	name: "Footer",
21 | 	components: { Version, Savings },
22 | 	props: {
23 | 		version: Object,
24 | 		savings: Object,
25 | 	},
26 | });
27 | </script>
28 | 


--------------------------------------------------------------------------------
/assets/js/components/Forecast/types.ts:
--------------------------------------------------------------------------------
 1 | export function isForecastSlot(obj?: TimeseriesEntry | ForecastSlot): obj is ForecastSlot {
 2 |   return (obj as ForecastSlot).start !== undefined;
 3 | }
 4 | 
 5 | export interface TimeseriesEntry {
 6 |   val: number;
 7 |   ts: string;
 8 | }
 9 | 
10 | export interface ForecastSlot {
11 |   start: string;
12 |   end: string;
13 |   value: number;
14 | }
15 | 
16 | export interface EnergyByDay {
17 |   energy: number;
18 |   complete: boolean;
19 | }
20 | 
21 | export interface SolarDetails {
22 |   scale?: number;
23 |   today?: EnergyByDay;
24 |   tomorrow?: EnergyByDay;
25 |   dayAfterTomorrow?: EnergyByDay;
26 |   timeseries?: TimeseriesEntry[];
27 | }
28 | 


--------------------------------------------------------------------------------
/assets/js/components/Helper/IconSelectGroup.vue:
--------------------------------------------------------------------------------
 1 | <template>
 2 | 	<div class="root border d-flex gap-1" role="group">
 3 | 		<slot></slot>
 4 | 	</div>
 5 | </template>
 6 | 
 7 | <script lang="ts">
 8 | import { defineComponent } from "vue";
 9 | 
10 | export default defineComponent({
11 | 	name: "IconSelectGroup",
12 | });
13 | </script>
14 | 
15 | <style scoped>
16 | .root {
17 | 	border-radius: 20px;
18 | 	padding: 4px;
19 | }
20 | </style>
21 | 


--------------------------------------------------------------------------------
/assets/js/components/Issue/types.d.ts:
--------------------------------------------------------------------------------
 1 | export interface IssueData {
 2 |   title: string;
 3 |   description: string;
 4 |   steps: string;
 5 |   version: string;
 6 | }
 7 | 
 8 | export interface SectionData {
 9 |   included: boolean;
10 |   content: string;
11 | }
12 | 
13 | export interface Sections {
14 |   yamlConfig: SectionData;
15 |   uiConfig: SectionData;
16 |   state: SectionData;
17 |   logs: SectionData;
18 | }
19 | 
20 | export interface GitHubContent {
21 |   body: string;
22 |   additional?: string;
23 | }
24 | 
25 | // First level items are joint with empty line (\n\n), second level with line wrap (\n)
26 | export type Template = (string | string[])[];
27 | 
28 | export type HelpType = "discussion" | "issue";
29 | 


--------------------------------------------------------------------------------
/assets/js/components/Loadpoints/SettingsButton.vue:
--------------------------------------------------------------------------------
 1 | <template>
 2 | 	<button
 3 | 		type="button"
 4 | 		class="btn btn-sm btn-outline-secondary position-relative border-0 p-2 evcc-gray"
 5 | 		data-testid="loadpoint-settings-button"
 6 | 	>
 7 | 		<shopicon-regular-adjust size="s"></shopicon-regular-adjust>
 8 | 	</button>
 9 | </template>
10 | 
11 | <script lang="ts">
12 | import "@h2d2/shopicons/es/regular/adjust";
13 | import { defineComponent } from "vue";
14 | 
15 | export default defineComponent({
16 | 	name: "LoadpointSettingsButton",
17 | 	props: {
18 | 		id: [String, Number],
19 | 	},
20 | });
21 | </script>
22 | 


--------------------------------------------------------------------------------
/assets/js/components/MaterialIcon/Add.vue:
--------------------------------------------------------------------------------
 1 | <template>
 2 | 	<svg :style="svgStyle" viewBox="0 0 24 24">
 3 | 		<path fill="currentColor" d="M11 13H5v-2h6V5h2v6h6v2h-6v6h-2z" />
 4 | 	</svg>
 5 | </template>
 6 | 
 7 | <script lang="ts">
 8 | import icon from "@/mixins/icon";
 9 | import { defineComponent } from "vue";
10 | 
11 | export default defineComponent({
12 | 	name: "Add",
13 | 	mixins: [icon],
14 | });
15 | </script>
16 | 


--------------------------------------------------------------------------------
/assets/js/components/MaterialIcon/Dropdown.vue:
--------------------------------------------------------------------------------
 1 | <template>
 2 | 	<svg :style="svgStyle" viewBox="0 0 24 24">
 3 | 		<path
 4 | 			fill="currentColor"
 5 | 			d="M11.475 14.475L7.85 10.85q-.075-.075-.112-.162T7.7 10.5q0-.2.138-.35T8.2 10h7.6q.225 0 .363.15t.137.35q0 .05-.15.35l-3.625 3.625q-.125.125-.25.175T12 14.7t-.275-.05t-.25-.175"
 6 | 		/>
 7 | 	</svg>
 8 | </template>
 9 | 
10 | <script lang="ts">
11 | import { defineComponent } from "vue";
12 | import icon from "@/mixins/icon";
13 | 
14 | export default defineComponent({
15 | 	name: "Dropdown",
16 | 	mixins: [icon],
17 | });
18 | </script>
19 | 


--------------------------------------------------------------------------------
/assets/js/components/MaterialIcon/DynamicPrice.vue:
--------------------------------------------------------------------------------
 1 | <template>
 2 | 	<svg :style="svgStyle" viewBox="0 0 24 24">
 3 | 		<g
 4 | 			fill="none"
 5 | 			stroke="currentColor"
 6 | 			stroke-linecap="round"
 7 | 			stroke-linejoin="round"
 8 | 			stroke-width="2"
 9 | 		>
10 | 			<circle cx="8" cy="8" r="6" />
11 | 			<path d="M18.09 10.37A6 6 0 1 1 10.34 18M7 6h1v4" />
12 | 			<path d="m16.71 13.88l.7.71l-2.82 2.82" />
13 | 		</g>
14 | 	</svg>
15 | </template>
16 | 
17 | <script lang="ts">
18 | import { defineComponent } from "vue";
19 | import icon from "@/mixins/icon";
20 | 
21 | export default defineComponent({
22 | 	name: "DynamicPrice",
23 | 	mixins: [icon],
24 | });
25 | </script>
26 | 


--------------------------------------------------------------------------------
/assets/js/components/MaterialIcon/Edit.vue:
--------------------------------------------------------------------------------
 1 | <template>
 2 | 	<svg :style="svgStyle" viewBox="0 0 24 24">
 3 | 		<path
 4 | 			fill="currentColor"
 5 | 			d="M5 19h1.425L16.2 9.225L14.775 7.8L5 17.575zm-1 2q-.425 0-.712-.288T3 20v-2.425q0-.4.15-.763t.425-.637L16.2 3.575q.3-.275.663-.425t.762-.15t.775.15t.65.45L20.425 5q.3.275.437.65T21 6.4q0 .4-.138.763t-.437.662l-12.6 12.6q-.275.275-.638.425t-.762.15zM19 6.4L17.6 5zm-3.525 2.125l-.7-.725L16.2 9.225z"
 6 | 		/>
 7 | 	</svg>
 8 | </template>
 9 | 
10 | <script lang="ts">
11 | import { defineComponent } from "vue";
12 | import icon from "@/mixins/icon";
13 | 
14 | export default defineComponent({
15 | 	name: "Edit",
16 | 	mixins: [icon],
17 | });
18 | </script>
19 | 


--------------------------------------------------------------------------------
/assets/js/components/MaterialIcon/PlanEnd.vue:
--------------------------------------------------------------------------------
 1 | <template>
 2 | 	<svg :style="svgStyle" viewBox="0 0 24 24">
 3 | 		<path
 4 | 			fill="currentColor"
 5 | 			d="M21 18q-.425 0-.712-.288T20 17V7q0-.425.288-.712T21 6t.713.288T22 7v10q0 .425-.288.713T21 18m-6.825-5H3q-.425 0-.712-.288T2 12t.288-.712T3 11h11.175L11.3 8.1q-.275-.275-.288-.687T11.3 6.7q.275-.275.7-.275t.7.275l4.6 4.6q.15.15.213.325t.062.375t-.062.375t-.213.325l-4.6 4.6q-.275.275-.687.275T11.3 17.3q-.3-.3-.3-.712t.3-.713z"
 6 | 		/>
 7 | 	</svg>
 8 | </template>
 9 | 
10 | <script lang="ts">
11 | import { defineComponent } from "vue";
12 | import icon from "@/mixins/icon";
13 | 
14 | export default defineComponent({
15 | 	name: "PlanEnd",
16 | 	mixins: [icon],
17 | });
18 | </script>
19 | 


--------------------------------------------------------------------------------
/assets/js/components/MaterialIcon/Play.vue:
--------------------------------------------------------------------------------
 1 | <template>
 2 | 	<svg :style="svgStyle" viewBox="0 0 24 24">
 3 | 		<path
 4 | 			fill="currentColor"
 5 | 			d="M8 17.175V6.825q0-.425.3-.713t.7-.287q.125 0 .263.037t.262.113l8.15 5.175q.225.15.338.375t.112.475t-.112.475t-.338.375l-8.15 5.175q-.125.075-.262.113T9 18.175q-.4 0-.7-.288t-.3-.712m2-1.825L15.25 12L10 8.65z"
 6 | 		/>
 7 | 	</svg>
 8 | </template>
 9 | 
10 | <script lang="ts">
11 | import { defineComponent } from "vue";
12 | import icon from "@/mixins/icon";
13 | 
14 | export default defineComponent({
15 | 	name: "Play",
16 | 	mixins: [icon],
17 | });
18 | </script>
19 | 


--------------------------------------------------------------------------------
/assets/js/components/MaterialIcon/Shm.vue:
--------------------------------------------------------------------------------
 1 | <template>
 2 | 	<svg :style="svgStyle" viewBox="0 0 32 32">
 3 | 		<path
 4 | 			d="M3.046,6.43c-1.365,-0 -2.513,1.149 -2.513,2.513l0,15.66c2.847,-1.757 15.172,-8.696 30.933,-8.411l0,-9.762l-28.42,-0Z"
 5 | 			fill="currentColor"
 6 | 		/>
 7 | 		<path
 8 | 			d="M1.5,25.57l27.454,0c1.365,0 2.513,-1.149 2.513,-2.513l-0.001,-5.568c-14.933,-0.278 -26.74,6.137 -29.965,8.082"
 9 | 			fill="currentColor"
10 | 		/>
11 | 	</svg>
12 | </template>
13 | 
14 | <script lang="ts">
15 | import { defineComponent } from "vue";
16 | import icon from "@/mixins/icon";
17 | 
18 | export default defineComponent({
19 | 	name: "Shm",
20 | 	mixins: [icon],
21 | });
22 | </script>
23 | 


--------------------------------------------------------------------------------
/assets/js/components/MaterialIcon/Total.vue:
--------------------------------------------------------------------------------
 1 | <template>
 2 | 	<svg :style="svgStyle" viewBox="0 0 24 24">
 3 | 		<path
 4 | 			fill="currentColor"
 5 | 			d="M4.83 4.61A1 1 0 0 1 5.75 4h12.5a1 1 0 1 1 0 2H8.11l4.95 5.115a1 1 0 0 1 .04 1.346L7.924 18.5H18.25a1 1 0 1 1 0 2H5.75a1 1 0 0 1-.76-1.65l5.999-6.999L5.03 5.695a1 1 0 0 1-.2-1.085"
 6 | 		/>
 7 | 	</svg>
 8 | </template>
 9 | 
10 | <script lang="ts">
11 | import { defineComponent } from "vue";
12 | import icon from "@/mixins/icon";
13 | 
14 | export default defineComponent({
15 | 	name: "Total",
16 | 	mixins: [icon],
17 | });
18 | </script>
19 | 


--------------------------------------------------------------------------------
/assets/js/components/MultiIcon/index.ts:
--------------------------------------------------------------------------------
1 | import MultiIcon from "./MultiIcon.vue";
2 | 
3 | export default MultiIcon;
4 | 


--------------------------------------------------------------------------------
/assets/js/components/Savings/LiveCommunity.stories.ts:
--------------------------------------------------------------------------------
 1 | import LiveCommunity from "./LiveCommunity.vue";
 2 | import type { Meta, StoryFn } from "@storybook/vue3";
 3 | 
 4 | export default {
 5 |   title: "Savings/LiveCommunity",
 6 |   component: LiveCommunity,
 7 |   parameters: {
 8 |     layout: "centered",
 9 |   },
10 | } as Meta<typeof LiveCommunity>;
11 | 
12 | const Template: StoryFn<typeof LiveCommunity> = () => ({
13 |   components: { LiveCommunity },
14 |   template: "<LiveCommunity />",
15 | });
16 | 
17 | export const Default = Template.bind({});
18 | 


--------------------------------------------------------------------------------
/assets/js/components/Savings/communityApi.ts:
--------------------------------------------------------------------------------
 1 | import axios from "axios";
 2 | 
 3 | const api = axios.create({
 4 |   baseURL: "https://api.evcc.io/v1/",
 5 |   headers: {
 6 |     Accept: "application/json",
 7 |   },
 8 | });
 9 | 
10 | // global error handling
11 | api.interceptors.response.use(
12 |   (response) => response,
13 |   (error) => {
14 |     const url = error.config.baseURL + error.config.url;
15 |     const message = `${error.message}: API request failed ${url}`;
16 |     window.app.raise({ message });
17 |     return Promise.reject(error);
18 |   }
19 | );
20 | 
21 | export default api;
22 | 


--------------------------------------------------------------------------------
/assets/js/components/Savings/types.d.ts:
--------------------------------------------------------------------------------
 1 | export interface LiveCommunityData {
 2 |   totalClients: number;
 3 |   activeClients: number;
 4 |   totalInstances: number;
 5 |   activeInstances: number;
 6 |   chargePower: number;
 7 |   greenPower: number;
 8 |   maxChargePower: number;
 9 |   maxGreenPower: number;
10 |   chargeEnergy: number;
11 |   greenEnergy: number;
12 | }
13 | export type Period = "30d" | "365d" | "thisYear" | "total";
14 | 


--------------------------------------------------------------------------------
/assets/js/components/Site/types.d.ts:
--------------------------------------------------------------------------------
1 | export interface Grid {
2 |   power?: number;
3 | }
4 | 


--------------------------------------------------------------------------------
/assets/js/components/Top/baseapi.ts:
--------------------------------------------------------------------------------
 1 | import axios from "axios";
 2 | 
 3 | const { protocol, hostname, port, pathname } = window.location;
 4 | 
 5 | const baseAPI = axios.create({
 6 |   baseURL: protocol + "//" + hostname + (port ? ":" + port : "") + pathname,
 7 | });
 8 | 
 9 | // global error handling
10 | baseAPI.interceptors.response.use(
11 |   (response) => response,
12 |   (error) => {
13 |     const url = error.config.baseURL + error.config.url;
14 |     const message = `${error.message}: API request failed ${url}`;
15 |     window.app.raise({ message });
16 |   }
17 | );
18 | 
19 | export default baseAPI;
20 | 


--------------------------------------------------------------------------------
/assets/js/components/Top/types.d.ts:
--------------------------------------------------------------------------------
1 | export interface Provider {
2 |   title: string;
3 |   authenticated: boolean;
4 |   loginPath: string;
5 |   logoutPath: string;
6 | }
7 | 


--------------------------------------------------------------------------------
/assets/js/components/VehicleIcon/Climate.vue:
--------------------------------------------------------------------------------
 1 | <template>
 2 | 	<svg width="1em" height="1em" viewBox="0 0 24 24">
 3 | 		<path
 4 | 			fill="currentColor"
 5 | 			d="M20 12H4q-.825 0-1.412-.587T2 10V4q0-.825.588-1.412T4 2h16q.825 0 1.413.588T22 4v6q0 .825-.587 1.413T20 12M4 19v-2q1.25 0 2.125-.875T7 14h2q0 2.075-1.463 3.538T4 19m16 0q-2.075 0-3.537-1.463T15 14h2q0 1.25.875 2.125T20 17zm-9 1v-6h2v6zm9-10H4zM6 10V8q0-.825.588-1.412T8 6h8q.825 0 1.413.588T18 8v2h-2V8H8v2zm-2 0h16V4H4z"
 6 | 		/>
 7 | 	</svg>
 8 | </template>
 9 | 
10 | <script lang="ts">
11 | import { defineComponent } from "vue";
12 | 
13 | export default defineComponent({
14 | 	name: "Climate",
15 | });
16 | </script>
17 | 


--------------------------------------------------------------------------------
/assets/js/components/VehicleIcon/Desktop.vue:
--------------------------------------------------------------------------------
 1 | <template>
 2 | 	<svg width="1em" height="1em" viewBox="0 0 24 24">
 3 | 		<path
 4 | 			fill="currentColor"
 5 | 			d="M10 19v-2H4q-.825 0-1.412-.587T2 15V5q0-.825.588-1.412T4 3h16q.825 0 1.413.588T22 5v10q0 .825-.587 1.413T20 17h-6v2h1q.425 0 .713.288T16 20t-.288.713T15 21H9q-.425 0-.712-.288T8 20t.288-.712T9 19zm-6-4h16V5H4zm0 0V5z"
 6 | 		/>
 7 | 	</svg>
 8 | </template>
 9 | 
10 | <script lang="ts">
11 | import { defineComponent } from "vue";
12 | export default defineComponent({
13 | 	name: "Desktop",
14 | });
15 | </script>
16 | 


--------------------------------------------------------------------------------
/assets/js/components/VehicleIcon/Floorlamp.vue:
--------------------------------------------------------------------------------
 1 | <template>
 2 | 	<svg width="1em" height="1em" viewBox="0 0 24 24">
 3 | 		<path
 4 | 			fill="currentColor"
 5 | 			d="M12 19q-.425 0-.712-.288T11 18v-7H6q-.5 0-.8-.4t-.15-.9L7 3.4q.2-.625.725-1.013T8.9 2h6.2q.65 0 1.175.388T17 3.4l1.95 6.3q.15.5-.15.9t-.8.4h-5v7q0 .425-.288.713T12 19M7.35 9h9.3L15.1 4H8.9zM9 22q-.425 0-.712-.288T8 21t.288-.712T9 20h6q.425 0 .713.288T16 21t-.288.713T15 22zm3-15.5"
 6 | 		/>
 7 | 	</svg>
 8 | </template>
 9 | 
10 | <script lang="ts">
11 | import { defineComponent } from "vue";
12 | export default defineComponent({
13 | 	name: "Floorlamp",
14 | });
15 | </script>
16 | 


--------------------------------------------------------------------------------
/assets/js/components/VehicleIcon/index.ts:
--------------------------------------------------------------------------------
1 | import VehicleIcon from "./VehicleIcon.vue";
2 | 
3 | export default VehicleIcon;
4 | 


--------------------------------------------------------------------------------
/assets/js/experimental.js:
--------------------------------------------------------------------------------
 1 | import settings from "./settings";
 2 | 
 3 | const KM = "km";
 4 | const MILES = "mi";
 5 | export const UNITS = [KM, MILES];
 6 | 
 7 | const MILES_FACTOR = 0.6213711922;
 8 | 
 9 | function isMiles() {
10 |   return settings.unit === MILES;
11 | }
12 | 
13 | export function distanceValue(value) {
14 |   return isMiles() ? value * MILES_FACTOR : value;
15 | }
16 | 
17 | export function distanceUnit() {
18 |   return isMiles() ? "mi" : "km";
19 | }
20 | 
21 | export function getUnits() {
22 |   return isMiles() ? MILES : KM;
23 | }
24 | 
25 | export function setUnits(value) {
26 |   settings.unit = value;
27 | }
28 | 


--------------------------------------------------------------------------------
/assets/js/featureflags.ts:
--------------------------------------------------------------------------------
 1 | import type { App } from "vue";
 2 | import settings from "./settings";
 3 | 
 4 | export function setHiddenFeatures(value: boolean) {
 5 |   settings.hiddenFeatures = value;
 6 | }
 7 | 
 8 | export function getHiddenFeatures() {
 9 |   return settings.hiddenFeatures;
10 | }
11 | 
12 | export default {
13 |   install: (app: App) => {
14 |     app.config.globalProperties.$hiddenFeatures = getHiddenFeatures;
15 |   },
16 | };
17 | 


--------------------------------------------------------------------------------
/assets/js/restart.ts:
--------------------------------------------------------------------------------
 1 | import { reactive } from "vue";
 2 | import api from "./api";
 3 | 
 4 | const restart = reactive({
 5 |   restartNeeded: false,
 6 |   restarting: false,
 7 | });
 8 | 
 9 | export async function performRestart() {
10 |   try {
11 |     await api.post("/system/shutdown");
12 |     restart.restarting = true;
13 |   } catch (e) {
14 |     alert(`Unable to restart server. ${e}`);
15 |   }
16 | }
17 | 
18 | export function restartComplete() {
19 |   restart.restarting = false;
20 |   restart.restartNeeded = false;
21 | }
22 | 
23 | export function showRestarting() {
24 |   restart.restarting = true;
25 | }
26 | 
27 | export default restart;
28 | 


--------------------------------------------------------------------------------
/assets/js/types/shopicons.d.ts:
--------------------------------------------------------------------------------
1 | declare module "@h2d2/shopicons/es/regular/*";
2 | declare module "@h2d2/shopicons/es/filled/*";
3 | 


--------------------------------------------------------------------------------
/assets/js/types/vue.d.ts:
--------------------------------------------------------------------------------
 1 | // eslint-disable-next-line @typescript-eslint/no-unused-vars
 2 | import type { ComponentCustomProperties } from "vue";
 3 | 
 4 | declare module "vue" {
 5 |   interface ComponentCustomProperties {
 6 |     /**
 7 |      * Whether experimental UI features should be shown.
 8 |      */
 9 |     $hiddenFeatures: () => boolean;
10 |     $refs: { [key: string]: HTMLElement | undefined };
11 |   }
12 | }
13 | 


--------------------------------------------------------------------------------
/assets/js/utils/convertRates.ts:
--------------------------------------------------------------------------------
 1 | import type { Rate } from "../types/evcc";
 2 | import type { ForecastSlot } from "../components/Forecast/types";
 3 | 
 4 | function convertRate(slot: ForecastSlot): Rate {
 5 |   return {
 6 |     start: new Date(slot.start),
 7 |     end: new Date(slot.end),
 8 |     value: slot.value,
 9 |   };
10 | }
11 | 
12 | export default function convertRates(slots: ForecastSlot[] | null): Rate[] {
13 |   if (!slots) return [];
14 |   return slots.map(convertRate);
15 | }
16 | 


--------------------------------------------------------------------------------
/assets/js/utils/debounce.ts:
--------------------------------------------------------------------------------
 1 | import type { Timeout } from "@/types/evcc";
 2 | 
 3 | export function debounce<T extends (...args: any[]) => any>(fn: T, delay: number): T {
 4 |   let timer: Timeout;
 5 |   return ((...args: any[]) => {
 6 |     if (timer) clearTimeout(timer);
 7 |     timer = setTimeout(() => fn(...args), delay);
 8 |   }) as T;
 9 | }
10 | 


--------------------------------------------------------------------------------
/assets/js/utils/deepClone.ts:
--------------------------------------------------------------------------------
1 | export default function <T>(obj: T): T {
2 |   return JSON.parse(JSON.stringify(obj));
3 | }
4 | 


--------------------------------------------------------------------------------
/assets/js/utils/deepEqual.ts:
--------------------------------------------------------------------------------
1 | export default function (obj1: any, obj2: any): boolean {
2 |   return JSON.stringify(obj1) === JSON.stringify(obj2);
3 | }
4 | 


--------------------------------------------------------------------------------
/assets/js/utils/fatal.ts:
--------------------------------------------------------------------------------
 1 | import type { FatalError } from "@/types/evcc";
 2 | 
 3 | const FATALS = ["configfile", "database"];
 4 | 
 5 | function isError(fatal: FatalError[]) {
 6 |   return fatal.length > 0;
 7 | }
 8 | 
 9 | export function isUserConfigError(fatal: FatalError[]) {
10 |   if (!isError(fatal)) {
11 |     return false;
12 |   }
13 | 
14 |   if (fatal.some((f) => FATALS.includes(f.class ?? ""))) {
15 |     return false;
16 |   }
17 | 
18 |   return true;
19 | }
20 | 
21 | export function isSystemError(fatal: FatalError[]) {
22 |   return isError(fatal) && !isUserConfigError(fatal);
23 | }
24 | 


--------------------------------------------------------------------------------
/assets/js/utils/log.ts:
--------------------------------------------------------------------------------
1 | export const LOG_LEVELS = ["fatal", "error", "warn", "info", "debug", "trace"] as const;
2 | export const DEFAULT_LOG_LEVEL = "debug";
3 | 
4 | export type LogLevel = (typeof LOG_LEVELS)[number];
5 | 


--------------------------------------------------------------------------------
/assets/js/utils/native.ts:
--------------------------------------------------------------------------------
 1 | export function isApp() {
 2 |   return navigator.userAgent.includes("evcc/");
 3 | }
 4 | 
 5 | export function appDetection() {
 6 |   if (isApp()) {
 7 |     const $html = document.querySelector("html");
 8 |     $html?.classList.add("app");
 9 |   }
10 | }
11 | 
12 | export function sendToApp(data: { type: string }) {
13 |   window.ReactNativeWebView?.postMessage(JSON.stringify(data));
14 | }
15 | 


--------------------------------------------------------------------------------
/assets/js/utils/sleep.ts:
--------------------------------------------------------------------------------
1 | export default (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
2 | 


--------------------------------------------------------------------------------
/assets/js/utils/useDebouncedComputed.ts:
--------------------------------------------------------------------------------
 1 | import { ref, watch, type Ref } from "vue";
 2 | import { debounce } from "./debounce";
 3 | 
 4 | export function useDebouncedComputed<T>(
 5 |   getter: () => T,
 6 |   deps: () => any,
 7 |   delay: number = 100
 8 | ): Ref<T> {
 9 |   const result = ref<T>();
10 |   const debouncedUpdate = debounce(() => {
11 |     result.value = getter();
12 |   }, delay);
13 | 
14 |   watch(deps, debouncedUpdate, { immediate: true, deep: true });
15 | 
16 |   return result as Ref<T>;
17 | }
18 | 


--------------------------------------------------------------------------------
/assets/public/meta/android-chrome-192x192-maskable.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evcc-io/evcc/2291b371e343043037ebef13c143a8c633eeb853/assets/public/meta/android-chrome-192x192-maskable.png


--------------------------------------------------------------------------------
/assets/public/meta/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evcc-io/evcc/2291b371e343043037ebef13c143a8c633eeb853/assets/public/meta/android-chrome-192x192.png


--------------------------------------------------------------------------------
/assets/public/meta/android-chrome-512x512-maskable.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evcc-io/evcc/2291b371e343043037ebef13c143a8c633eeb853/assets/public/meta/android-chrome-512x512-maskable.png


--------------------------------------------------------------------------------
/assets/public/meta/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evcc-io/evcc/2291b371e343043037ebef13c143a8c633eeb853/assets/public/meta/android-chrome-512x512.png


--------------------------------------------------------------------------------
/assets/public/meta/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evcc-io/evcc/2291b371e343043037ebef13c143a8c633eeb853/assets/public/meta/apple-touch-icon.png


--------------------------------------------------------------------------------
/assets/public/meta/browserconfig.xml:
--------------------------------------------------------------------------------
 1 | <?xml version="1.0" encoding="utf-8"?>
 2 | <browserconfig>
 3 |   <msapplication>
 4 |     <tile>
 5 |       <square70x70logo src="meta/mstile-70x70.png" />
 6 |       <square150x150logo src="meta/mstile-150x150.png" />
 7 |       <square310x310logo src="meta/mstile-310x310.png" />
 8 |       <TileColor>#1C2445</TileColor>
 9 |     </tile>
10 |   </msapplication>
11 | </browserconfig>


--------------------------------------------------------------------------------
/assets/public/meta/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evcc-io/evcc/2291b371e343043037ebef13c143a8c633eeb853/assets/public/meta/favicon-16x16.png


--------------------------------------------------------------------------------
/assets/public/meta/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evcc-io/evcc/2291b371e343043037ebef13c143a8c633eeb853/assets/public/meta/favicon-32x32.png


--------------------------------------------------------------------------------
/assets/public/meta/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evcc-io/evcc/2291b371e343043037ebef13c143a8c633eeb853/assets/public/meta/favicon.ico


--------------------------------------------------------------------------------
/assets/public/meta/mstile-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evcc-io/evcc/2291b371e343043037ebef13c143a8c633eeb853/assets/public/meta/mstile-144x144.png


--------------------------------------------------------------------------------
/assets/public/meta/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evcc-io/evcc/2291b371e343043037ebef13c143a8c633eeb853/assets/public/meta/mstile-150x150.png


--------------------------------------------------------------------------------
/assets/public/meta/mstile-310x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evcc-io/evcc/2291b371e343043037ebef13c143a8c633eeb853/assets/public/meta/mstile-310x150.png


--------------------------------------------------------------------------------
/assets/public/meta/mstile-310x310.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evcc-io/evcc/2291b371e343043037ebef13c143a8c633eeb853/assets/public/meta/mstile-310x310.png


--------------------------------------------------------------------------------
/assets/public/meta/mstile-70x70.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evcc-io/evcc/2291b371e343043037ebef13c143a8c633eeb853/assets/public/meta/mstile-70x70.png


--------------------------------------------------------------------------------
/charger/config.go:
--------------------------------------------------------------------------------
 1 | package charger
 2 | 
 3 | import (
 4 | 	"context"
 5 | 
 6 | 	"github.com/evcc-io/evcc/api"
 7 | 	"github.com/evcc-io/evcc/charger/config"
 8 | )
 9 | 
10 | var registry = config.Registry
11 | 
12 | // Types returns the list of types
13 | func Types() []string {
14 | 	return registry.Types()
15 | }
16 | 
17 | // NewFromConfig creates charger from configuration
18 | func NewFromConfig(ctx context.Context, typ string, other map[string]any) (api.Charger, error) {
19 | 	return config.NewFromConfig(ctx, typ, other)
20 | }
21 | 


--------------------------------------------------------------------------------
/charger/config/config.go:
--------------------------------------------------------------------------------
 1 | package config
 2 | 
 3 | import (
 4 | 	"context"
 5 | 	"fmt"
 6 | 	"strings"
 7 | 
 8 | 	"github.com/evcc-io/evcc/api"
 9 | 	reg "github.com/evcc-io/evcc/util/registry"
10 | )
11 | 
12 | var Registry = reg.New[api.Charger]("charger")
13 | 
14 | // NewFromConfig creates charger from configuration
15 | func NewFromConfig(ctx context.Context, typ string, other map[string]any) (api.Charger, error) {
16 | 	factory, err := Registry.Get(strings.ToLower(typ))
17 | 	if err != nil {
18 | 		return nil, err
19 | 	}
20 | 
21 | 	v, err := factory(ctx, other)
22 | 	if err != nil {
23 | 		return nil, fmt.Errorf("cannot create charger type '%s': %w", typ, err)
24 | 	}
25 | 
26 | 	return v, nil
27 | }
28 | 


--------------------------------------------------------------------------------
/charger/connectiq/types.go:
--------------------------------------------------------------------------------
 1 | package connectiq
 2 | 
 3 | type ChargeStatus struct {
 4 | 	Amps   int64  `json:"amps"`
 5 | 	Pp     int64  `json:"pp"`
 6 | 	Status string `json:"status"`
 7 | 	Std    int64  `json:"std"`
 8 | }
 9 | 
10 | type ChargeMaxAmps struct {
11 | 	Max int64 `json:"max"`
12 | }
13 | 
14 | type MeterStatus struct {
15 | 	App  []float64 `json:"app"`
16 | 	Curr []float64 `json:"curr"`
17 | 	Fac  []float64 `json:"fac"`
18 | 	Pow  []float64 `json:"pow"`
19 | 	Volt []float64 `json:"volt"`
20 | }
21 | 
22 | type MeterRead struct {
23 | 	Energy float64 `json:"energy"`
24 | }
25 | 


--------------------------------------------------------------------------------
/charger/echarge/types.go:
--------------------------------------------------------------------------------
1 | package echarge
2 | 
3 | const (
4 | 	ModeEco    = "eco"
5 | 	ModeManual = "manual"
6 | )
7 | 


--------------------------------------------------------------------------------
/charger/embed.go:
--------------------------------------------------------------------------------
 1 | package charger
 2 | 
 3 | import (
 4 | 	"github.com/evcc-io/evcc/api"
 5 | )
 6 | 
 7 | type embed struct {
 8 | 	Icon_     string        `mapstructure:"icon"`
 9 | 	Features_ []api.Feature `mapstructure:"features"`
10 | }
11 | 
12 | var _ api.IconDescriber = (*embed)(nil)
13 | 
14 | // Icon implements the api.IconDescriber interface
15 | func (v *embed) Icon() string {
16 | 	return v.Icon_
17 | }
18 | 
19 | var _ api.FeatureDescriber = (*embed)(nil)
20 | 
21 | // Features implements the api.FeatureDescriber interface
22 | func (v *embed) Features() []api.Feature {
23 | 	return v.Features_
24 | }
25 | 


--------------------------------------------------------------------------------
/charger/measurement/energy.go:
--------------------------------------------------------------------------------
 1 | package measurement
 2 | 
 3 | import (
 4 | 	"context"
 5 | 	"fmt"
 6 | 
 7 | 	"github.com/evcc-io/evcc/plugin"
 8 | )
 9 | 
10 | type Energy struct {
11 | 	Power  *plugin.Config // optional
12 | 	Energy *plugin.Config // optional
13 | }
14 | 
15 | func (cc *Energy) Configure(ctx context.Context) (
16 | 	func() (float64, error),
17 | 	func() (float64, error),
18 | 	error,
19 | ) {
20 | 	powerG, err := cc.Power.FloatGetter(ctx)
21 | 	if err != nil {
22 | 		return nil, nil, fmt.Errorf("power: %w", err)
23 | 	}
24 | 
25 | 	energyG, err := cc.Energy.FloatGetter(ctx)
26 | 	if err != nil {
27 | 		return nil, nil, fmt.Errorf("energy: %w", err)
28 | 	}
29 | 
30 | 	return powerG, energyG, nil
31 | }
32 | 


--------------------------------------------------------------------------------
/charger/nrgble.go:
--------------------------------------------------------------------------------
 1 | //go:build !linux
 2 | 
 3 | package charger
 4 | 
 5 | import (
 6 | 	"errors"
 7 | 
 8 | 	"github.com/evcc-io/evcc/api"
 9 | )
10 | 
11 | func init() {
12 | 	registry.Add("nrgkick-bluetooth", NewNRGKickBLEFromConfig)
13 | }
14 | 
15 | // NewNRGKickBLEFromConfig creates a NRGKickBLE charger from generic config
16 | func NewNRGKickBLEFromConfig(other map[string]any) (api.Charger, error) {
17 | 	return nil, errors.New("NRGKick bluetooth is only supported on linux")
18 | }
19 | 


--------------------------------------------------------------------------------
/charger/ocpp/helper_test.go:
--------------------------------------------------------------------------------
 1 | package ocpp
 2 | 
 3 | import (
 4 | 	"testing"
 5 | 	"time"
 6 | 
 7 | 	"github.com/lorenzodonini/ocpp-go/ocpp1.6/types"
 8 | 	"github.com/stretchr/testify/assert"
 9 | )
10 | 
11 | func TestSortByAge(t *testing.T) {
12 | 	assert.Equal(t, []types.MeterValue{
13 | 		{Timestamp: nil},
14 | 		{Timestamp: types.NewDateTime(time.UnixMilli(1))},
15 | 		{Timestamp: types.NewDateTime(time.UnixMilli(2))},
16 | 		{Timestamp: types.NewDateTime(time.UnixMilli(3))},
17 | 	}, sortByAge([]types.MeterValue{
18 | 		{Timestamp: types.NewDateTime(time.UnixMilli(3))},
19 | 		{Timestamp: types.NewDateTime(time.UnixMilli(1))},
20 | 		{Timestamp: nil},
21 | 		{Timestamp: types.NewDateTime(time.UnixMilli(2))},
22 | 	}))
23 | }
24 | 


--------------------------------------------------------------------------------
/charger/template.go:
--------------------------------------------------------------------------------
 1 | package charger
 2 | 
 3 | import (
 4 | 	"context"
 5 | 
 6 | 	"github.com/evcc-io/evcc/api"
 7 | 	"github.com/evcc-io/evcc/util/templates"
 8 | )
 9 | 
10 | func init() {
11 | 	registry.AddCtx("template", NewChargerFromTemplateConfig)
12 | }
13 | 
14 | func NewChargerFromTemplateConfig(ctx context.Context, other map[string]any) (api.Charger, error) {
15 | 	instance, err := templates.RenderInstance(templates.Charger, other)
16 | 	if err != nil {
17 | 		return nil, err
18 | 	}
19 | 
20 | 	return NewFromConfig(ctx, instance.Type, instance.Other)
21 | }
22 | 


--------------------------------------------------------------------------------
/charger/warp/const.go:
--------------------------------------------------------------------------------
1 | package warp
2 | 
3 | import "time"
4 | 
5 | const (
6 | 	RootTopic = "warp"
7 | 	Timeout   = 30 * time.Second
8 | )
9 | 


--------------------------------------------------------------------------------
/cmd/cache.go:
--------------------------------------------------------------------------------
 1 | package cmd
 2 | 
 3 | import (
 4 | 	"github.com/spf13/cobra"
 5 | )
 6 | 
 7 | // cacheCmd represents the cache command
 8 | var cacheCmd = &cobra.Command{
 9 | 	Use:   "cache",
10 | 	Short: "Manage cache entries",
11 | }
12 | 
13 | func init() {
14 | 	rootCmd.AddCommand(cacheCmd)
15 | }
16 | 


--------------------------------------------------------------------------------
/cmd/demo.go:
--------------------------------------------------------------------------------
 1 | package cmd
 2 | 
 3 | import (
 4 | 	_ "embed" // for yaml
 5 | 	"fmt"
 6 | 	"strings"
 7 | 
 8 | 	"github.com/evcc-io/evcc/api/globalconfig"
 9 | )
10 | 
11 | //go:embed demo.yaml
12 | var demoYaml string
13 | 
14 | func demoConfig(conf *globalconfig.All) error {
15 | 	viper.SetConfigType("yaml")
16 | 	if err := viper.ReadConfig(strings.NewReader(demoYaml)); err != nil {
17 | 		return fmt.Errorf("failed decoding demo config: %w", err)
18 | 	}
19 | 
20 | 	if err := viper.UnmarshalExact(conf); err != nil {
21 | 		return fmt.Errorf("failed loading demo config: %w", err)
22 | 	}
23 | 
24 | 	// parse log levels after reading config
25 | 	parseLogLevels()
26 | 
27 | 	return nil
28 | }
29 | 


--------------------------------------------------------------------------------
/cmd/detect/analyze.go:
--------------------------------------------------------------------------------
 1 | package detect
 2 | 
 3 | import "github.com/evcc-io/evcc/cmd/detect/tasks"
 4 | 
 5 | type Criteria map[string]any
 6 | 
 7 | type TypeSummary struct {
 8 | 	Results       []tasks.Result
 9 | 	Found, Unique bool
10 | }
11 | 
12 | type Summary struct {
13 | 	Charger, Grid, PV, Charge, Battery, Meter TypeSummary
14 | }
15 | 


--------------------------------------------------------------------------------
/cmd/detect/tasks/const.go:
--------------------------------------------------------------------------------
1 | package tasks
2 | 
3 | import "time"
4 | 
5 | const timeout = 200 * time.Millisecond
6 | 


--------------------------------------------------------------------------------
/cmd/discuss.tpl:
--------------------------------------------------------------------------------
 1 | <!-- Detaillierte Problembeschreibung bitte hier -->
 2 | 
 3 | 
 4 | 
 5 | {{ if .CfgError -}}
 6 | Fehlermeldung:
 7 | 
 8 | ```
 9 | {{ .CfgError }}
10 | ```
11 | 
12 | {{ end -}}
13 | 
14 | {{ if .CfgContent -}}
15 | <details><summary>Konfiguration{{ if .CfgFile }} ({{ .CfgFile }}){{ end }}</summary>
16 | 
17 | ```yaml
18 | {{ .CfgContent }}
19 | ```
20 | 
21 | </details>
22 | {{ end -}}
23 | 
24 | {{ if .Version -}}
25 | Version: `{{ .Version }}`
26 | {{ end -}}
27 | 


--------------------------------------------------------------------------------
/cmd/dump.tpl:
--------------------------------------------------------------------------------
 1 | 
 2 | {{ if .CfgError -}}
 3 | Fehlermeldung:
 4 | 
 5 | {{ .CfgError | indent 4 }}
 6 | 
 7 | {{ end -}}
 8 | 
 9 | {{ if .CfgContent -}}
10 | Konfiguration{{ if .CfgFile }} ({{ .CfgFile }}){{ end }}:
11 | 
12 | {{ .CfgContent }}
13 | 
14 | {{ end -}}
15 | 
16 | {{ if .Version -}}
17 | Version: `{{ .Version }}`
18 | {{ end -}}
19 | 


--------------------------------------------------------------------------------
/cmd/error_test.go:
--------------------------------------------------------------------------------
 1 | package cmd
 2 | 
 3 | import (
 4 | 	"errors"
 5 | 	"testing"
 6 | 
 7 | 	"github.com/stretchr/testify/require"
 8 | )
 9 | 
10 | func TestError(t *testing.T) {
11 | 	res := &ClassError{
12 | 		ClassMeter,
13 | 		&DeviceError{
14 | 			"0815",
15 | 			errors.New("foo"),
16 | 		},
17 | 	}
18 | 
19 | 	b, err := res.MarshalJSON()
20 | 	require.NoError(t, err)
21 | 	require.Equal(t, `{"class":"meter","device":"0815","error":"[0815] foo"}`, string(b))
22 | }
23 | 


--------------------------------------------------------------------------------
/cmd/openapi/openapi.go:
--------------------------------------------------------------------------------
 1 | package main
 2 | 
 3 | import (
 4 | 	"encoding/json"
 5 | 	"log"
 6 | 	"os"
 7 | 
 8 | 	"github.com/getkin/kin-openapi/openapi3"
 9 | )
10 | 
11 | func main() {
12 | 	doc, err := openapi3.NewLoader().LoadFromFile(os.Args[1])
13 | 	if err != nil {
14 | 		log.Fatal("failed to load OpenAPI spec:", err)
15 | 	}
16 | 
17 | 	// omit servers
18 | 	doc.Servers = nil
19 | 
20 | 	b, err := json.MarshalIndent(doc, "", "  ")
21 | 	if err != nil {
22 | 		log.Fatal(err)
23 | 	}
24 | 
25 | 	if err := os.WriteFile(os.Args[2], b, 0o644); err != nil {
26 | 		log.Fatal(err)
27 | 	}
28 | }
29 | 


--------------------------------------------------------------------------------
/cmd/password.go:
--------------------------------------------------------------------------------
 1 | package cmd
 2 | 
 3 | import (
 4 | 	"github.com/spf13/cobra"
 5 | )
 6 | 
 7 | var passwordCmd = &cobra.Command{
 8 | 	Use:   "password",
 9 | 	Short: "Password administration",
10 | }
11 | 
12 | func init() {
13 | 	rootCmd.AddCommand(passwordCmd)
14 | }
15 | 


--------------------------------------------------------------------------------
/cmd/settings.go:
--------------------------------------------------------------------------------
 1 | package cmd
 2 | 
 3 | import (
 4 | 	"github.com/spf13/cobra"
 5 | )
 6 | 
 7 | // settingsCmd represents the configure command
 8 | var settingsCmd = &cobra.Command{
 9 | 	Use:   "settings",
10 | 	Short: "Manage configuration settings",
11 | }
12 | 
13 | func init() {
14 | 	rootCmd.AddCommand(settingsCmd)
15 | }
16 | 


--------------------------------------------------------------------------------
/cmd/shutdown/shutdown.go:
--------------------------------------------------------------------------------
 1 | package shutdown
 2 | 
 3 | import (
 4 | 	"sync"
 5 | )
 6 | 
 7 | var (
 8 | 	mu       sync.Mutex
 9 | 	handlers = make([]func(), 0)
10 | )
11 | 
12 | // Register registers a function for executing on application shutdown
13 | func Register(cb func()) {
14 | 	mu.Lock()
15 | 	handlers = append(handlers, cb)
16 | 	mu.Unlock()
17 | }
18 | 
19 | // Cleanup executes the registered shutdown functions when the stop channel closes
20 | func Cleanup(doneC chan struct{}) {
21 | 	var wg sync.WaitGroup
22 | 
23 | 	mu.Lock()
24 | 	for _, cb := range handlers {
25 | 		wg.Go(cb)
26 | 	}
27 | 	mu.Unlock()
28 | 
29 | 	wg.Wait()
30 | 	close(doneC)
31 | }
32 | 


--------------------------------------------------------------------------------
/cmd/sponsor.go:
--------------------------------------------------------------------------------
 1 | package cmd
 2 | 
 3 | import (
 4 | 	"github.com/evcc-io/evcc/util/sponsor"
 5 | 	"github.com/spf13/cobra"
 6 | )
 7 | 
 8 | // sponsorCmd represents the vehicle command
 9 | var sponsorCmd = &cobra.Command{
10 | 	Use:   "sponsor [name]",
11 | 	Short: "Validate sponsor token",
12 | 	Args:  cobra.ExactArgs(1),
13 | 	Run:   runSponsor,
14 | }
15 | 
16 | func init() {
17 | 	rootCmd.AddCommand(sponsorCmd)
18 | }
19 | 
20 | func runSponsor(cmd *cobra.Command, args []string) {
21 | 	token := args[0]
22 | 
23 | 	if err := sponsor.ConfigureSponsorship(token); err != nil {
24 | 		fatal(err)
25 | 	}
26 | 
27 | 	log.INFO.Println("sponsorship validated")
28 | }
29 | 


--------------------------------------------------------------------------------
/core/circuit/config.go:
--------------------------------------------------------------------------------
 1 | package circuit
 2 | 
 3 | import (
 4 | 	"github.com/evcc-io/evcc/api"
 5 | 	"github.com/evcc-io/evcc/util/config"
 6 | )
 7 | 
 8 | func Root() api.Circuit {
 9 | 	for _, dev := range config.Circuits().Devices() {
10 | 		if c := dev.Instance(); c.GetParent() == nil {
11 | 			return c
12 | 		}
13 | 	}
14 | 	return nil
15 | }
16 | 


--------------------------------------------------------------------------------
/core/coordinator/dummy.go:
--------------------------------------------------------------------------------
 1 | package coordinator
 2 | 
 3 | import (
 4 | 	"github.com/evcc-io/evcc/api"
 5 | 	"github.com/evcc-io/evcc/core/loadpoint"
 6 | )
 7 | 
 8 | type dummy struct{}
 9 | 
10 | // NewDummy creates a dummy coordinator without vehicles
11 | func NewDummy() API {
12 | 	return new(dummy)
13 | }
14 | 
15 | func (a *dummy) GetVehicles(_ bool) []api.Vehicle {
16 | 	return nil
17 | }
18 | 
19 | func (a *dummy) Owner(api.Vehicle) loadpoint.API {
20 | 	return nil
21 | }
22 | 
23 | func (a *dummy) Acquire(api.Vehicle) {}
24 | 
25 | func (a *dummy) Release(api.Vehicle) {}
26 | 
27 | func (a *dummy) IdentifyVehicleByStatus() api.Vehicle {
28 | 	return nil
29 | }
30 | 


--------------------------------------------------------------------------------
/core/keys/auth.go:
--------------------------------------------------------------------------------
1 | package keys
2 | 
3 | const (
4 | 	AdminPassword = "adminPassword"
5 | 	JwtSecret     = "jwtSecretKey"
6 | )
7 | 


--------------------------------------------------------------------------------
/core/loadpoint/error.go:
--------------------------------------------------------------------------------
 1 | package loadpoint
 2 | 
 3 | import (
 4 | 	"errors"
 5 | 
 6 | 	"github.com/evcc-io/evcc/api"
 7 | )
 8 | 
 9 | func AcceptableError(err error) bool {
10 | 	for _, e := range []error{api.ErrAsleep, api.ErrMustRetry, api.ErrNotAvailable} {
11 | 		if errors.Is(err, e) {
12 | 			return true
13 | 		}
14 | 	}
15 | 	return false
16 | }
17 | 


--------------------------------------------------------------------------------
/core/metrics/types.go:
--------------------------------------------------------------------------------
 1 | package metrics
 2 | 
 3 | import (
 4 | 	"database/sql"
 5 | 	"errors"
 6 | 	"time"
 7 | )
 8 | 
 9 | type SqlTime time.Time
10 | 
11 | var _ sql.Scanner = (*SqlTime)(nil)
12 | 
13 | func (st *SqlTime) Scan(value any) error {
14 | 	switch v := value.(type) {
15 | 	case time.Time:
16 | 		*st = SqlTime(v)
17 | 	case int64:
18 | 		*st = SqlTime(time.Unix(v, 0))
19 | 	case string:
20 | 		t, err := time.Parse(time.DateTime+"-07:00", v)
21 | 		if err == nil {
22 | 			*st = SqlTime(t)
23 | 		}
24 | 		return err
25 | 	default:
26 | 		return errors.New("unsupported timestamp type")
27 | 	}
28 | 	return nil
29 | }
30 | 


--------------------------------------------------------------------------------
/core/planner/sort.go:
--------------------------------------------------------------------------------
 1 | package planner
 2 | 
 3 | import "github.com/evcc-io/evcc/api"
 4 | 
 5 | // sortByCost is a sortFunc for slices.Sort
 6 | func sortByCost(i, j api.Rate) int {
 7 | 	switch {
 8 | 	case i.Value < j.Value:
 9 | 		return -1
10 | 	case i.Value > j.Value:
11 | 		return +1
12 | 	default:
13 | 		return j.Start.Compare(i.Start)
14 | 	}
15 | }
16 | 


--------------------------------------------------------------------------------
/core/progress.go:
--------------------------------------------------------------------------------
 1 | package core
 2 | 
 3 | type Progress struct {
 4 | 	min, step, current float64
 5 | }
 6 | 
 7 | func NewProgress(min, step float64) *Progress {
 8 | 	return &Progress{
 9 | 		min:     min,
10 | 		step:    step,
11 | 		current: min,
12 | 	}
13 | }
14 | 
15 | func (p *Progress) NextStep(value float64) bool {
16 | 	// test guard
17 | 	if p != nil && value >= p.current {
18 | 		for p.current <= value {
19 | 			p.current += p.step
20 | 		}
21 | 
22 | 		return true
23 | 	}
24 | 
25 | 	return false
26 | }
27 | 
28 | func (p *Progress) Reset() {
29 | 	// test guard
30 | 	if p != nil {
31 | 		p.current = p.min
32 | 	}
33 | }
34 | 


--------------------------------------------------------------------------------
/core/progress_test.go:
--------------------------------------------------------------------------------
 1 | package core
 2 | 
 3 | import (
 4 | 	"fmt"
 5 | 	"testing"
 6 | 
 7 | 	"github.com/stretchr/testify/require"
 8 | )
 9 | 
10 | func TestProgress(t *testing.T) {
11 | 	p := NewProgress(0, 10)
12 | 
13 | 	tc := []struct {
14 | 		value float64
15 | 		res   bool
16 | 	}{
17 | 		{-1, false},
18 | 		{0, true},
19 | 		{1, false},
20 | 		{5, false},
21 | 		{10, true},
22 | 		{15, false},
23 | 		{25, true},
24 | 		{30, true},
25 | 		{60, true},
26 | 		{65, false},
27 | 		{70, true},
28 | 	}
29 | 
30 | 	for _, tc := range tc {
31 | 		require.Equal(t, tc.res, p.NextStep(tc.value), fmt.Sprintf("%.0f%%", tc.value))
32 | 	}
33 | }
34 | 


--------------------------------------------------------------------------------
/core/session/format_test.go:
--------------------------------------------------------------------------------
 1 | package session
 2 | 
 3 | import (
 4 | 	"testing"
 5 | 
 6 | 	"github.com/stretchr/testify/assert"
 7 | 	"golang.org/x/text/language"
 8 | 	"golang.org/x/text/message"
 9 | )
10 | 
11 | func TestFormatValue(t *testing.T) {
12 | 	mp := message.NewPrinter(language.Make("en"))
13 | 
14 | 	f := 1.2345
15 | 	assert.Equal(t, "1.234", formatValue(mp, f, 3))
16 | 	assert.Equal(t, "1.234", formatValue(mp, &f, 3))
17 | }
18 | 


--------------------------------------------------------------------------------
/core/settings/settings.go:
--------------------------------------------------------------------------------
 1 | package settings
 2 | 
 3 | import "time"
 4 | 
 5 | type Settings interface {
 6 | 	SetString(key string, val string)
 7 | 	SetInt(key string, val int64)
 8 | 	SetFloat(key string, val float64)
 9 | 	SetFloatPtr(key string, val *float64)
10 | 	SetTime(key string, val time.Time)
11 | 	SetJson(key string, val any) error
12 | 	SetBool(key string, val bool)
13 | 	String(key string) (string, error)
14 | 	Int(key string) (int64, error)
15 | 	Float(key string) (float64, error)
16 | 	Time(key string) (time.Time, error)
17 | 	Bool(key string) (bool, error)
18 | 	Json(key string, res any) error
19 | }
20 | 


--------------------------------------------------------------------------------
/core/site/vehicles.go:
--------------------------------------------------------------------------------
 1 | package site
 2 | 
 3 | import (
 4 | 	"github.com/evcc-io/evcc/api"
 5 | 	"github.com/evcc-io/evcc/core/vehicle"
 6 | )
 7 | 
 8 | type Vehicles interface {
 9 | 	// Settings returns the list of vehicle adapters
10 | 	Settings() []vehicle.API
11 | 
12 | 	// ByName returns a single vehicle adapter by name
13 | 	ByName(string) (vehicle.API, error)
14 | 
15 | 	// All returns the list of vehicle instances
16 | 	Instances() []api.Vehicle
17 | }
18 | 


--------------------------------------------------------------------------------
/core/soc/helper.go:
--------------------------------------------------------------------------------
 1 | package soc
 2 | 
 3 | import "fmt"
 4 | 
 5 | // Guard checks soc value for validity
 6 | func Guard(soc float64, err error) (float64, error) {
 7 | 	switch {
 8 | 	case err != nil:
 9 | 		return soc, err
10 | 
11 | 	case soc < 0:
12 | 		return 0, fmt.Errorf("invalid soc: %.1f", soc)
13 | 
14 | 	case soc > 100:
15 | 		return 100, fmt.Errorf("invalid soc: %.1f", soc)
16 | 
17 | 	default:
18 | 		return soc, nil
19 | 	}
20 | }
21 | 


--------------------------------------------------------------------------------
/core/wrapper/chargemeter.go:
--------------------------------------------------------------------------------
 1 | package wrapper
 2 | 
 3 | import (
 4 | 	"sync"
 5 | )
 6 | 
 7 | // ChargeMeter is a replacement for a physical charge meter.
 8 | // It uses the charger's actual or max current to calculate power consumption.
 9 | type ChargeMeter struct {
10 | 	sync.Mutex
11 | 	power float64
12 | }
13 | 
14 | // SetPower updates meter's current power
15 | func (m *ChargeMeter) SetPower(power float64) {
16 | 	m.Lock()
17 | 	defer m.Unlock()
18 | 	m.power = power
19 | }
20 | 
21 | // CurrentPower implements the api.Meter interface
22 | func (m *ChargeMeter) CurrentPower() (float64, error) {
23 | 	m.Lock()
24 | 	defer m.Unlock()
25 | 	return m.power, nil
26 | }
27 | 


--------------------------------------------------------------------------------
/core/wrapper/chargemeter_test.go:
--------------------------------------------------------------------------------
 1 | package wrapper
 2 | 
 3 | import (
 4 | 	"testing"
 5 | 
 6 | 	"go.uber.org/mock/gomock"
 7 | )
 8 | 
 9 | func TestProxyChargeMeter(t *testing.T) {
10 | 	ctrl := gomock.NewController(t)
11 | 	defer ctrl.Finish()
12 | 
13 | 	tc := []float64{600, 1000, 2000}
14 | 	m := ChargeMeter{}
15 | 
16 | 	for _, f := range tc {
17 | 		m.SetPower(f)
18 | 
19 | 		if p, err := m.CurrentPower(); p != f || err != nil {
20 | 			t.Errorf("power: %.1f %v", p, err)
21 | 		}
22 | 	}
23 | }
24 | 


--------------------------------------------------------------------------------
/core/wrapper/chargetimer_test.go:
--------------------------------------------------------------------------------
 1 | package wrapper
 2 | 
 3 | import (
 4 | 	"testing"
 5 | 	"time"
 6 | 
 7 | 	"github.com/benbjohnson/clock"
 8 | )
 9 | 
10 | func TestTimer(t *testing.T) {
11 | 	ct := NewChargeTimer()
12 | 	clck := clock.NewMock()
13 | 	ct.clck = clck
14 | 
15 | 	ct.StartCharge(false)
16 | 	clck.Add(time.Hour)
17 | 	ct.StopCharge()
18 | 	clck.Add(time.Hour)
19 | 
20 | 	if d, err := ct.ChargeDuration(); d != 1*time.Hour || err != nil {
21 | 		t.Error(d, err)
22 | 	}
23 | 
24 | 	// continue
25 | 	ct.StartCharge(true)
26 | 	clck.Add(2 * time.Hour)
27 | 	ct.StopCharge()
28 | 
29 | 	if d, err := ct.ChargeDuration(); d != 3*time.Hour || err != nil {
30 | 		t.Error(d, err)
31 | 	}
32 | }
33 | 


--------------------------------------------------------------------------------
/env.d.ts:
--------------------------------------------------------------------------------
1 | /// <reference types="vite/client" />
2 | 


--------------------------------------------------------------------------------
/hems/eebus/types.go:
--------------------------------------------------------------------------------
 1 | package eebus
 2 | 
 3 | type status int
 4 | 
 5 | const (
 6 | 	StatusUnlimited status = iota
 7 | 	StatusLimited
 8 | 	StatusFailsafe
 9 | )
10 | 


--------------------------------------------------------------------------------
/i18n/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | 	"jsonRecursiveSort": true,
3 | 	"plugins": ["prettier-plugin-sort-json"]
4 | }
5 | 


--------------------------------------------------------------------------------
/i18n/et.json:
--------------------------------------------------------------------------------
1 | {
2 |   "batterySettings": {
3 |     "batteryLevel": "Akutase",
4 |     "capacity": "{energy} / {total}",
5 |     "control": "Akuhaldus"
6 |   }
7 | }
8 | 


--------------------------------------------------------------------------------
/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evcc-io/evcc/2291b371e343043037ebef13c143a8c633eeb853/icon.png


--------------------------------------------------------------------------------
/jest.config.ts:
--------------------------------------------------------------------------------
1 | import { Config } from "@jest/types";
2 | 
3 | export default {
4 |   preset: "@vue/cli-plugin-unit-jest/presets/no-babel",
5 |   testMatch: ["**/*.spec.ts"],
6 | } satisfies Config.InitialOptions;
7 | 


--------------------------------------------------------------------------------
/meter/bosch/types.go:
--------------------------------------------------------------------------------
 1 | package bosch
 2 | 
 3 | type LoginResponse struct {
 4 | 	wuSid string
 5 | }
 6 | 
 7 | type StatusResponse struct {
 8 | 	CurrentBatterySoc     float64
 9 | 	SellToGrid            float64
10 | 	BuyFromGrid           float64
11 | 	PvPower               float64
12 | 	BatteryChargePower    float64
13 | 	BatteryDischargePower float64
14 | }
15 | 


--------------------------------------------------------------------------------
/meter/config.go:
--------------------------------------------------------------------------------
 1 | package meter
 2 | 
 3 | import (
 4 | 	"context"
 5 | 
 6 | 	"github.com/evcc-io/evcc/api"
 7 | 	"github.com/evcc-io/evcc/meter/config"
 8 | )
 9 | 
10 | var registry = config.Registry
11 | 
12 | // Types returns the list of types
13 | func Types() []string {
14 | 	return registry.Types()
15 | }
16 | 
17 | // NewFromConfig creates meter from configuration
18 | func NewFromConfig(ctx context.Context, typ string, other map[string]any) (api.Meter, error) {
19 | 	return config.NewFromConfig(ctx, typ, other)
20 | }
21 | 


--------------------------------------------------------------------------------
/meter/config/config.go:
--------------------------------------------------------------------------------
 1 | package config
 2 | 
 3 | import (
 4 | 	"context"
 5 | 	"fmt"
 6 | 	"strings"
 7 | 
 8 | 	"github.com/evcc-io/evcc/api"
 9 | 	reg "github.com/evcc-io/evcc/util/registry"
10 | )
11 | 
12 | var Registry = reg.New[api.Meter]("meter")
13 | 
14 | // NewFromConfig creates meter from configuration
15 | func NewFromConfig(ctx context.Context, typ string, other map[string]any) (api.Meter, error) {
16 | 	factory, err := Registry.Get(strings.ToLower(typ))
17 | 	if err != nil {
18 | 		return nil, err
19 | 	}
20 | 
21 | 	v, err := factory(ctx, other)
22 | 	if err != nil {
23 | 		return nil, fmt.Errorf("cannot create meter type '%s': %w", typ, err)
24 | 	}
25 | 
26 | 	return v, nil
27 | }
28 | 


--------------------------------------------------------------------------------
/meter/discovergy/types.go:
--------------------------------------------------------------------------------
 1 | package discovergy
 2 | 
 3 | const API = "https://api.inexogy.com/public/v1"
 4 | 
 5 | type Meter struct {
 6 | 	MeterID          string `json:"meterId"`
 7 | 	SerialNumber     string `json:"serialNumber"`
 8 | 	FullSerialNumber string `json:"fullSerialNumber"`
 9 | }
10 | 
11 | type Reading struct {
12 | 	Time   int64
13 | 	Values struct {
14 | 		EnergyOut                    int64
15 | 		Energy1, Energy2             int64
16 | 		Voltage1, Voltage2, Voltage3 int64
17 | 		EnergyOut1, EnergyOut2       int64
18 | 		Power1, Power2, Power3       int64
19 | 		Power                        int64
20 | 		Energy                       int64
21 | 	}
22 | }
23 | 


--------------------------------------------------------------------------------
/meter/goodwe/types.go:
--------------------------------------------------------------------------------
 1 | package goodwe
 2 | 
 3 | import (
 4 | 	"net"
 5 | 
 6 | 	"github.com/evcc-io/evcc/util"
 7 | )
 8 | 
 9 | type Server struct {
10 | 	log       *util.Logger
11 | 	conn      *net.UDPConn
12 | 	inverters map[string]*util.Monitor[Inverter]
13 | }
14 | 
15 | type Inverter struct {
16 | 	PvPower      float64
17 | 	NetPower     float64
18 | 	BatteryPower float64
19 | 	Soc          float64
20 | }
21 | 


--------------------------------------------------------------------------------
/meter/measurement/energy.go:
--------------------------------------------------------------------------------
 1 | package measurement
 2 | 
 3 | import (
 4 | 	"context"
 5 | 	"fmt"
 6 | 
 7 | 	"github.com/evcc-io/evcc/plugin"
 8 | )
 9 | 
10 | type Energy struct {
11 | 	Power  plugin.Config
12 | 	Energy *plugin.Config // optional
13 | }
14 | 
15 | func (cc *Energy) Configure(ctx context.Context) (
16 | 	func() (float64, error),
17 | 	func() (float64, error),
18 | 	error,
19 | ) {
20 | 	powerG, err := cc.Power.FloatGetter(ctx)
21 | 	if err != nil {
22 | 		return nil, nil, fmt.Errorf("power: %w", err)
23 | 	}
24 | 
25 | 	energyG, err := cc.Energy.FloatGetter(ctx)
26 | 	if err != nil {
27 | 		return nil, nil, fmt.Errorf("energy: %w", err)
28 | 	}
29 | 
30 | 	return powerG, energyG, nil
31 | }
32 | 


--------------------------------------------------------------------------------
/meter/mystrom.go:
--------------------------------------------------------------------------------
 1 | package meter
 2 | 
 3 | import (
 4 | 	"github.com/evcc-io/evcc/api"
 5 | 	"github.com/evcc-io/evcc/meter/mystrom"
 6 | 	"github.com/evcc-io/evcc/util"
 7 | )
 8 | 
 9 | // myStrom switch:
10 | // https://api.mystrom.ch/#fbb2c698-e37a-4584-9324-3f8b2f615fe2
11 | 
12 | func init() {
13 | 	registry.Add("mystrom", NewMyStromFromConfig)
14 | }
15 | 
16 | // NewMyStromFromConfig creates a myStrom meter from generic config
17 | func NewMyStromFromConfig(other map[string]any) (api.Meter, error) {
18 | 	var cc struct {
19 | 		URI string
20 | 	}
21 | 
22 | 	if err := util.DecodeOther(other, &cc); err != nil {
23 | 		return nil, err
24 | 	}
25 | 
26 | 	return mystrom.NewConnection(cc.URI), nil
27 | }
28 | 


--------------------------------------------------------------------------------
/meter/obis/obis.go:
--------------------------------------------------------------------------------
 1 | package obis
 2 | 
 3 | // https://www.kbr.de/de/obis-kennzeichen/elektrizitaet
 4 | 
 5 | const (
 6 | 	PowerConsumption  = "1-0:1.4.0"
 7 | 	EnergyConsumption = "1-0:1.8.0"
 8 | 	PowerFeedIn       = "1-0:2.4.0"
 9 | 	EnergyFeedIn      = "1-0:2.8.0"
10 | 
11 | 	PowerConsumptionL1  = "1-0:21.4.0"
12 | 	EnergyConsumptionL1 = "1-0:21.8.0"
13 | 	CurrentL1           = "1-0:31.4.0"
14 | 
15 | 	PowerConsumptionL2  = "1-0:41.4.0"
16 | 	EnergyConsumptionL2 = "1-0:41.8.0"
17 | 	CurrentL2           = "1-0:51.4.0"
18 | 
19 | 	PowerConsumptionL3  = "1-0:61.4.0"
20 | 	EnergyConsumptionL3 = "1-0:61.8.0"
21 | 	CurrentL3           = "1-0:71.4.0"
22 | )
23 | 


--------------------------------------------------------------------------------
/meter/shelly/types.go:
--------------------------------------------------------------------------------
 1 | package shelly
 2 | 
 3 | // DeviceInfo is the common /shelly endpoint response
 4 | // https://shelly-api-docs.shelly.cloud/gen1/#shelly
 5 | // https://shelly-api-docs.shelly.cloud/gen2/ComponentsAndServices/Shelly#http-endpoint-shelly
 6 | type DeviceInfo struct {
 7 | 	Mac       string `json:"mac"`
 8 | 	Gen       int    `json:"gen"`
 9 | 	Model     string `json:"model"`
10 | 	Type      string `json:"type"`
11 | 	Auth      bool   `json:"auth"`
12 | 	AuthEn    bool   `json:"auth_en"`
13 | 	NumMeters int    `json:"num_meters"`
14 | 	Profile   string `json:"profile"`
15 | }
16 | 


--------------------------------------------------------------------------------
/meter/template.go:
--------------------------------------------------------------------------------
 1 | package meter
 2 | 
 3 | import (
 4 | 	"context"
 5 | 
 6 | 	"github.com/evcc-io/evcc/api"
 7 | 	"github.com/evcc-io/evcc/util/templates"
 8 | )
 9 | 
10 | func init() {
11 | 	registry.AddCtx("template", NewMeterFromTemplateConfig)
12 | }
13 | 
14 | func NewMeterFromTemplateConfig(ctx context.Context, other map[string]any) (api.Meter, error) {
15 | 	instance, err := templates.RenderInstance(templates.Meter, other)
16 | 	if err != nil {
17 | 		return nil, err
18 | 	}
19 | 
20 | 	return NewFromConfig(ctx, instance.Type, instance.Other)
21 | }
22 | 


--------------------------------------------------------------------------------
/meter/tplink.go:
--------------------------------------------------------------------------------
 1 | package meter
 2 | 
 3 | import (
 4 | 	"github.com/evcc-io/evcc/api"
 5 | 	"github.com/evcc-io/evcc/meter/tplink"
 6 | 	"github.com/evcc-io/evcc/util"
 7 | )
 8 | 
 9 | func init() {
10 | 	registry.Add("tplink", NewTPLinkFromConfig)
11 | }
12 | 
13 | // NewTPLinkFromConfig creates a tapo meter from generic config
14 | func NewTPLinkFromConfig(other map[string]any) (api.Meter, error) {
15 | 	var cc struct {
16 | 		URI string
17 | 	}
18 | 
19 | 	if err := util.DecodeOther(other, &cc); err != nil {
20 | 		return nil, err
21 | 	}
22 | 
23 | 	return tplink.NewConnection(cc.URI)
24 | }
25 | 


--------------------------------------------------------------------------------
/meter/usage_pv.go:
--------------------------------------------------------------------------------
 1 | package meter
 2 | 
 3 | type pvMaxACPower struct {
 4 | 	MaxACPower float64
 5 | }
 6 | 
 7 | // var _ api.MaxACPowerGetter = (*pvMaxACPower)(nil)
 8 | 
 9 | // Decorator returns the max AC power decorator
10 | func (m *pvMaxACPower) Decorator() func() float64 {
11 | 	if m.MaxACPower == 0 {
12 | 		return nil
13 | 	}
14 | 	return func() float64 {
15 | 		return m.MaxACPower
16 | 	}
17 | }
18 | 


--------------------------------------------------------------------------------
/packaging/init/evcc.service:
--------------------------------------------------------------------------------
 1 | # evcc.service
 2 | #
 3 | 
 4 | [Unit]
 5 | Description=evcc
 6 | Requires=network-online.target
 7 | After=syslog.target network.target network-online.target
 8 | Wants=network-online.target
 9 | StartLimitIntervalSec=10
10 | StartLimitBurst=10
11 | 
12 | [Service]
13 | AmbientCapabilities=CAP_NET_BIND_SERVICE
14 | ExecStart=/usr/bin/evcc
15 | Environment="EVCC_DATABASE_DSN=/var/lib/evcc/evcc.db"
16 | Restart=always
17 | RestartSec=10
18 | 
19 | User=evcc
20 | Group=evcc
21 | 
22 | [Install]
23 | WantedBy=multi-user.target
24 | 


--------------------------------------------------------------------------------
/packaging/patch/asn1.diff:
--------------------------------------------------------------------------------
 1 | --- asn1.go	2022-09-15 13:21:17.000000000 +0200
 2 | +++ asn1_new.go	2022-09-15 13:22:12.000000000 +0200
 3 | @@ -255,7 +255,7 @@
 4 |  	switch bytes[0] {
 5 |  	case 0:
 6 |  		*out = false
 7 | -	case 0xff:
 8 | +	case 1, 0xff:
 9 |  		*out = true
10 |  	default:
11 |  		return false
12 | 


--------------------------------------------------------------------------------
/packaging/scripts/preremove.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | set -e
3 | 
4 | if [ -d /run/systemd/system ] && [ "$1" = remove ]; then
5 | 	deb-systemd-invoke stop evcc.service > /dev/null || true
6 | fi
7 | 


--------------------------------------------------------------------------------
/plugin/auth/config.go:
--------------------------------------------------------------------------------
 1 | package auth
 2 | 
 3 | import (
 4 | 	"context"
 5 | 	"fmt"
 6 | 	"strings"
 7 | 
 8 | 	reg "github.com/evcc-io/evcc/util/registry"
 9 | 	"golang.org/x/oauth2"
10 | )
11 | 
12 | var registry = reg.New[oauth2.TokenSource]("auth")
13 | 
14 | // NewFromConfig creates auth from configuration
15 | func NewFromConfig(ctx context.Context, typ string, other map[string]any) (oauth2.TokenSource, error) {
16 | 	factory, err := registry.Get(strings.ToLower(typ))
17 | 	if err != nil {
18 | 		return nil, err
19 | 	}
20 | 
21 | 	v, err := factory(ctx, other)
22 | 	if err != nil {
23 | 		err = fmt.Errorf("cannot create auth type '%s': %w", typ, err)
24 | 	}
25 | 
26 | 	return v, err
27 | }
28 | 


--------------------------------------------------------------------------------
/plugin/golang/stdlib/generate.go:
--------------------------------------------------------------------------------
 1 | package stdlib
 2 | 
 3 | import "reflect"
 4 | 
 5 | // go:generate yaegi extract fmt
 6 | // go:generate yaegi extract math
 7 | // go:generate yaegi extract strings
 8 | // go:generate yaegi extract time
 9 | 
10 | // Symbols variable stores the map of stdlib symbols per package.
11 | var Symbols = map[string]map[string]reflect.Value{}
12 | 


--------------------------------------------------------------------------------
/plugin/http_limit.go:
--------------------------------------------------------------------------------
 1 | package plugin
 2 | 
 3 | import "sync"
 4 | 
 5 | var (
 6 | 	httpMu      sync.Mutex
 7 | 	httpMutexes = map[string]*sync.Mutex{}
 8 | )
 9 | 
10 | func muForKey(key string) *sync.Mutex {
11 | 	httpMu.Lock()
12 | 	defer httpMu.Unlock()
13 | 
14 | 	if mu, ok := httpMutexes[key]; ok {
15 | 		return mu
16 | 	}
17 | 
18 | 	mu := new(sync.Mutex)
19 | 	httpMutexes[key] = mu
20 | 	return mu
21 | }
22 | 


--------------------------------------------------------------------------------
/plugin/method.go:
--------------------------------------------------------------------------------
 1 | package plugin
 2 | 
 3 | //go:generate go tool enumer -type Method -text
 4 | type Method int
 5 | 
 6 | const (
 7 | 	_ Method = iota
 8 | 	Energy
 9 | 	Power
10 | 	Soc
11 | )
12 | 


--------------------------------------------------------------------------------
/prettier.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import("prettier").Config} */
2 | export default {
3 |   printWidth: 100,
4 |   trailingComma: "es5",
5 |   plugins: ["prettier-plugin-sh"],
6 | };
7 | 


--------------------------------------------------------------------------------
/server/assets/assets.go:
--------------------------------------------------------------------------------
 1 | package assets
 2 | 
 3 | import "io/fs"
 4 | 
 5 | var (
 6 | 	// Web is the embedded dist file system
 7 | 	Web fs.FS
 8 | 
 9 | 	// I18n is the embedded i18n file system
10 | 	I18n fs.FS
11 | )
12 | 
13 | // Live indicates assets are passed-through from filesystem
14 | func Live() bool {
15 | 	return Web != nil
16 | }
17 | 


--------------------------------------------------------------------------------
/server/assets/assets_live.go:
--------------------------------------------------------------------------------
 1 | //go:build !release
 2 | 
 3 | package assets
 4 | 
 5 | import (
 6 | 	"os"
 7 | )
 8 | 
 9 | func init() {
10 | 	Web = os.DirFS("dist")
11 | 	I18n = os.DirFS("i18n")
12 | }
13 | 


--------------------------------------------------------------------------------
/server/db/settings/api.go:
--------------------------------------------------------------------------------
1 | package settings
2 | 
3 | //go:generate go tool mockgen -package settings -destination mock.go -mock_names API=MockAPI github.com/evcc-io/evcc/server/db/settings API
4 | 
5 | type API interface {
6 | 	String(key string) (string, error)
7 | 	SetString(key string, value string)
8 | }
9 | 


--------------------------------------------------------------------------------
/server/eebus/eebus_test.go:
--------------------------------------------------------------------------------
 1 | package eebus
 2 | 
 3 | import (
 4 | 	"testing"
 5 | 
 6 | 	"github.com/stretchr/testify/require"
 7 | 	"go.yaml.in/yaml/v4"
 8 | )
 9 | 
10 | func TestConfig(t *testing.T) {
11 | 	conf := `
12 | certificate:
13 |   private: |
14 |     -----BEGIN EC PRIVATE KEY-----
15 |     MHcCfoo==
16 |     -----END EC PRIVATE KEY-----
17 |   public: |
18 |     -----BEGIN CERTIFICATE-----
19 |     MIIBbar=
20 |     -----END CERTIFICATE-----
21 | `
22 | 
23 | 	var res Config
24 | 	require.NoError(t, yaml.Unmarshal([]byte(conf), &res))
25 | }
26 | 


--------------------------------------------------------------------------------
/server/eebus/helper.go:
--------------------------------------------------------------------------------
 1 | package eebus
 2 | 
 3 | import (
 4 | 	"errors"
 5 | 
 6 | 	eebusapi "github.com/enbility/eebus-go/api"
 7 | 	"github.com/evcc-io/evcc/api"
 8 | )
 9 | 
10 | func WrapError(err error) error {
11 | 	if errors.Is(err, eebusapi.ErrDataNotAvailable) {
12 | 		return api.ErrNotAvailable
13 | 	}
14 | 	return err
15 | }
16 | 


--------------------------------------------------------------------------------
/server/eebus/types.go:
--------------------------------------------------------------------------------
 1 | package eebus
 2 | 
 3 | import "github.com/evcc-io/evcc/util"
 4 | 
 5 | const (
 6 | 	BrandName string = "EVCC"
 7 | 	Model     string = "HEMS"
 8 | )
 9 | 
10 | // used as common name in cert generation
11 | var DeviceCode = util.Getenv("EEBUS_DEVICE_CODE", "EVCC_HEMS_01")
12 | 
13 | type Config struct {
14 | 	URI         string
15 | 	ShipID      string
16 | 	Interfaces  []string
17 | 	Certificate struct {
18 | 		Public, Private string
19 | 	}
20 | }
21 | 
22 | // Configured returns true if the EEbus server is configured
23 | func (c Config) Configured() bool {
24 | 	return len(c.Certificate.Public) > 0 && len(c.Certificate.Private) > 0
25 | }
26 | 


--------------------------------------------------------------------------------
/server/log.go:
--------------------------------------------------------------------------------
1 | package server
2 | 
3 | import "github.com/evcc-io/evcc/util"
4 | 
5 | var log = util.NewLogger("server")
6 | 


--------------------------------------------------------------------------------
/server/mcp/tools.go:
--------------------------------------------------------------------------------
 1 | package mcp
 2 | 
 3 | import (
 4 | 	"context"
 5 | 
 6 | 	"github.com/modelcontextprotocol/go-sdk/mcp"
 7 | )
 8 | 
 9 | func docsTool(_ context.Context, _ *mcp.CallToolRequest, _ any) (*mcp.CallToolResult, any, error) {
10 | 	return &mcp.CallToolResult{
11 | 		Content: []mcp.Content{
12 | 			&mcp.ResourceLink{
13 | 				URI:      "https://docs.evcc.io",
14 | 				Name:     "evcc-docs",
15 | 				Title:    "evcc documentation",
16 | 				MIMEType: "text/html",
17 | 			},
18 | 		},
19 | 	}, nil, nil
20 | }
21 | 


--------------------------------------------------------------------------------
/server/modbus/readonlymode.go:
--------------------------------------------------------------------------------
 1 | package modbus
 2 | 
 3 | // go:generate go tool enumer -type ReadOnlyMode -trimprefix ReadOnly -transform=lower
 4 | 
 5 | type ReadOnlyMode int
 6 | 
 7 | const (
 8 | 	ReadOnlyFalse ReadOnlyMode = iota
 9 | 	ReadOnlyDeny
10 | 	ReadOnlyTrue
11 | )
12 | 


--------------------------------------------------------------------------------
/server/openapi.go:
--------------------------------------------------------------------------------
1 | package server
2 | 
3 | //go:generate go tool openapi openapi.yaml mcp/openapi.json
4 | //go:generate go tool openapi-mcp --doc mcp/openapi.md openapi.yaml
5 | 


--------------------------------------------------------------------------------
/server/openapi_test.go:
--------------------------------------------------------------------------------
 1 | package server
 2 | 
 3 | import (
 4 | 	"testing"
 5 | 
 6 | 	"github.com/getkin/kin-openapi/openapi3"
 7 | 	"github.com/stretchr/testify/require"
 8 | )
 9 | 
10 | func TestOpenAPIValidation(t *testing.T) {
11 | 	loader := openapi3.NewLoader()
12 | 	doc, err := loader.LoadFromFile("openapi.yaml")
13 | 	require.NoError(t, err)
14 | 	require.NoError(t, doc.Validate(loader.Context))
15 | }
16 | 


--------------------------------------------------------------------------------
/server/product.go:
--------------------------------------------------------------------------------
 1 | package server
 2 | 
 3 | type product struct {
 4 | 	Name     string `json:"name"`
 5 | 	Template string `json:"template"`
 6 | 	Group    string `json:"group,omitempty"`
 7 | }
 8 | 
 9 | type products []product
10 | 


--------------------------------------------------------------------------------
/server/uds_windows.go:
--------------------------------------------------------------------------------
 1 | //go:build windows
 2 | 
 3 | package server
 4 | 
 5 | import "github.com/evcc-io/evcc/core/site"
 6 | 
 7 | // HealthListener attaches listener to unix domain socket
 8 | func HealthListener(_ site.API) {
 9 | 	// nop
10 | }
11 | 


--------------------------------------------------------------------------------
/server/updater/run.go:
--------------------------------------------------------------------------------
 1 | //go:build !gokrazy
 2 | 
 3 | package updater
 4 | 
 5 | import (
 6 | 	"github.com/evcc-io/evcc/util"
 7 | 	"github.com/google/go-github/v32/github"
 8 | )
 9 | 
10 | // Run regularly checks version
11 | func Run(log *util.Logger, httpd webServer, outChan chan<- util.Param) {
12 | 	u := &watch{
13 | 		log:     log,
14 | 		outChan: outChan,
15 | 		repo:    NewRepo(log, owner, repository),
16 | 	}
17 | 
18 | 	c := make(chan *github.RepositoryRelease, 1)
19 | 	go u.watchReleases(util.Version, c) // endless
20 | 
21 | 	for rel := range c {
22 | 		u.Send("availableVersion", *rel.TagName)
23 | 	}
24 | }
25 | 


--------------------------------------------------------------------------------
/tariff/elering/types.go:
--------------------------------------------------------------------------------
 1 | package elering
 2 | 
 3 | const URI = "https://dashboard.elering.ee/api"
 4 | 
 5 | type NpsPrice struct {
 6 | 	Success bool
 7 | 	Data    map[string][]Price
 8 | }
 9 | 
10 | type Price struct {
11 | 	Timestamp int64
12 | 	Price     float64
13 | }
14 | 


--------------------------------------------------------------------------------
/tariff/octopus/graphql/errors.go:
--------------------------------------------------------------------------------
 1 | package graphql
 2 | 
 3 | import (
 4 | 	"errors"
 5 | )
 6 | 
 7 | var (
 8 | 	ErrAccountNotFound  = errors.New("unable to find configured account")
 9 | 	ErrMultipleAccounts = errors.New("multiple accounts on this api key - specific an account to use in configuration")
10 | 	ErrNoAccounts       = errors.New("no accounts on this api key")
11 | )
12 | 


--------------------------------------------------------------------------------
/tariff/proxy_cache_error.go:
--------------------------------------------------------------------------------
 1 | package tariff
 2 | 
 3 | import "github.com/evcc-io/evcc/api"
 4 | 
 5 | type proxyError struct {
 6 | 	error
 7 | }
 8 | 
 9 | var _ api.Tariff = (*proxyError)(nil)
10 | 
11 | func (t *proxyError) Rates() (api.Rates, error) {
12 | 	return api.Rates{}, t.error
13 | }
14 | 
15 | func (t *proxyError) Type() api.TariffType {
16 | 	return 0 // unknown
17 | }
18 | 


--------------------------------------------------------------------------------
/tariff/smartenergy/types.go:
--------------------------------------------------------------------------------
 1 | package smartenergy
 2 | 
 3 | import "time"
 4 | 
 5 | const URI = "https://apis.smartenergy.at/market/v1/price"
 6 | 
 7 | type Prices struct {
 8 | 	Data []Price
 9 | }
10 | 
11 | type Price struct {
12 | 	Date  time.Time
13 | 	Value float64
14 | }
15 | 


--------------------------------------------------------------------------------
/tariff/template.go:
--------------------------------------------------------------------------------
 1 | package tariff
 2 | 
 3 | import (
 4 | 	"context"
 5 | 
 6 | 	"github.com/evcc-io/evcc/api"
 7 | 	"github.com/evcc-io/evcc/util/templates"
 8 | )
 9 | 
10 | func init() {
11 | 	registry.AddCtx("template", NewTariffFromTemplateConfig)
12 | }
13 | 
14 | func NewTariffFromTemplateConfig(ctx context.Context, other map[string]any) (api.Tariff, error) {
15 | 	instance, err := templates.RenderInstance(templates.Tariff, other)
16 | 	if err != nil {
17 | 		return nil, err
18 | 	}
19 | 
20 | 	return NewProxyFromConfig(ctx, instance.Type, instance.Other)
21 | }
22 | 


--------------------------------------------------------------------------------
/tariff/types.go:
--------------------------------------------------------------------------------
 1 | package tariff
 2 | 
 3 | type Typed struct {
 4 | 	Type   string         `json:"type"`
 5 | 	Tariff string         `json:"tariff"`
 6 | 	Other  map[string]any `mapstructure:",remain" yaml:",inline"`
 7 | }
 8 | 
 9 | func (t Typed) Name() string {
10 | 	if t.Type == "template" {
11 | 		return t.Tariff
12 | 	}
13 | 	return t.Type
14 | }
15 | 
16 | type FromTo struct {
17 | 	From, To int
18 | }
19 | 
20 | func (ft FromTo) IsActive(hour int) bool {
21 | 	return ft.From == 0 && ft.To == 0 ||
22 | 		ft.From < ft.To && ft.From <= hour && hour <= ft.To ||
23 | 		ft.From > ft.To && (ft.From <= hour || hour <= ft.To)
24 | }
25 | 


--------------------------------------------------------------------------------
/templates/definition/charger/abb.yaml:
--------------------------------------------------------------------------------
 1 | template: abb
 2 | products:
 3 |   - brand: ABB
 4 |     description:
 5 |       generic: Terra AC
 6 | capabilities: ["mA"]
 7 | requirements:
 8 |   description:
 9 |     de: Erfordert Firmware >= 1.6.5
10 |     en: Requires firmware >= 1.6.5
11 |   evcc: ["sponsorship"]
12 | params:
13 |   - name: modbus
14 |     choice: ["rs485", "tcpip"]
15 | render: |
16 |   type: abb
17 |   {{- include "modbus" . }}
18 | 


--------------------------------------------------------------------------------
/templates/definition/charger/abl-em4.yaml:
--------------------------------------------------------------------------------
 1 | template: abl-em4
 2 | products:
 3 |   - brand: ABL
 4 |     description:
 5 |       generic: eM4 Single (SBCx)
 6 |   - brand: ABL
 7 |     description:
 8 |       generic: eM4 Twin (SBCx)
 9 | capabilities: ["mA"]
10 | requirements:
11 |   evcc: ["sponsorship"]
12 | params:
13 |   - name: modbus
14 |     choice: ["tcpip"]
15 |     id: 255
16 |   - name: connector
17 |     default: 1
18 | render: |
19 |   type: abl-em4
20 |   {{- include "modbus" . }}
21 |   connector: {{ .connector }}
22 | 


--------------------------------------------------------------------------------
/templates/definition/charger/abl.yaml:
--------------------------------------------------------------------------------
 1 | template: abl
 2 | products:
 3 |   - brand: ABL
 4 |     description:
 5 |       generic: eMH1
 6 |   - brand: ABL
 7 |     description:
 8 |       generic: eMH2
 9 |   - brand: SENEC
10 |     description:
11 |       generic: Wallbox pro
12 | capabilities: ["mA"]
13 | requirements:
14 |   evcc: ["sponsorship"]
15 | params:
16 |   - name: modbus
17 |     choice: ["rs485"]
18 |     baudrate: 38400
19 |     comset: 8E1
20 |   - name: timeout
21 | render: |
22 |   type: abl
23 |   {{- include "modbus" . }}
24 |   timeout: {{ .timeout }}
25 | 


--------------------------------------------------------------------------------
/templates/definition/charger/alpitronic.yaml:
--------------------------------------------------------------------------------
 1 | template: alpitronic
 2 | products:
 3 |   - brand: Alpitronic
 4 |     description:
 5 |       generic: Hypercharger
 6 | capabilities: ["mA", "rfid", "iso151182"]
 7 | requirements:
 8 |   evcc: ["sponsorship"]
 9 | params:
10 |   - name: modbus
11 |     choice: ["tcpip"]
12 |   - name: connector
13 |     default: 1
14 | render: |
15 |   type: alpitronic
16 |   {{- include "modbus" . }}
17 |   connector: {{ .connector }}
18 | 


--------------------------------------------------------------------------------
/templates/definition/charger/amperfied-solar.yaml:
--------------------------------------------------------------------------------
 1 | template: amperfied-solar
 2 | products:
 3 |   - brand: Amperfied
 4 |     description:
 5 |       generic: Wallbox connect.solar
 6 | capabilities: ["mA", "rfid", "1p3p"]
 7 | requirements:
 8 |   evcc: ["sponsorship"]
 9 | params:
10 |   - name: modbus
11 |     choice: ["tcpip"]
12 |     id: 255
13 | render: |
14 |   type: amperfied
15 |   {{- include "modbus" . }}
16 |   phases1p3p: true
17 | 


--------------------------------------------------------------------------------
/templates/definition/charger/amperfied.yaml:
--------------------------------------------------------------------------------
 1 | template: amperfied
 2 | products:
 3 |   - brand: Amperfied
 4 |     description:
 5 |       generic: Wallbox connect.home
 6 |   - brand: Amperfied
 7 |     description:
 8 |       generic: Wallbox connect.business
 9 | capabilities: ["mA", "rfid"]
10 | requirements:
11 |   evcc: ["sponsorship"]
12 | params:
13 |   - name: modbus
14 |     choice: ["tcpip"]
15 |     id: 255
16 | render: |
17 |   type: amperfied
18 |   {{- include "modbus" . }}
19 | 


--------------------------------------------------------------------------------
/templates/definition/charger/compleo-duo.yaml:
--------------------------------------------------------------------------------
 1 | template: compleo-duo
 2 | products:
 3 |   - brand: Compleo
 4 |     description:
 5 |       generic: Duo
 6 | capabilities: ["mA", "rfid", "1p3p"]
 7 | requirements:
 8 |   evcc: ["sponsorship"]
 9 | params:
10 |   - name: modbus
11 |     choice: ["tcpip"]
12 |   - name: connector
13 | render: |
14 |   type: compleo
15 |   {{- include "modbus" . }}
16 |   connector: {{ .connector }}
17 | 


--------------------------------------------------------------------------------
/templates/definition/charger/compleo-solo.yaml:
--------------------------------------------------------------------------------
 1 | template: compleo-solo
 2 | products:
 3 |   - brand: Compleo
 4 |     description:
 5 |       generic: Solo
 6 | capabilities: ["mA", "rfid"]
 7 | requirements:
 8 |   evcc: ["sponsorship"]
 9 | params:
10 |   - name: modbus
11 |     choice: ["tcpip"]
12 | render: |
13 |   type: compleo
14 |   {{- include "modbus" . }}
15 | 


--------------------------------------------------------------------------------
/templates/definition/charger/dadapower.yaml:
--------------------------------------------------------------------------------
 1 | template: dadapower
 2 | products:
 3 |   - brand: Dadapower
 4 |     description:
 5 |       generic: Premium Wallbox
 6 | capabilities: ["1p3p", "mA", "rfid"]
 7 | requirements:
 8 |   evcc: ["sponsorship"]
 9 | params:
10 |   - name: modbus
11 |     choice: ["tcpip"]
12 |     id: 1
13 | render: |
14 |   type: dadapower
15 |   {{- include "modbus" . }}
16 | 


--------------------------------------------------------------------------------
/templates/definition/charger/daheimladen-pro.yaml:
--------------------------------------------------------------------------------
 1 | template: daheimladen-pro
 2 | products:
 3 |   - brand: DaheimLaden
 4 |     description:
 5 |       generic: Smart/Touch Pro
 6 | requirements:
 7 |   description:
 8 |     de: Die Phasenumschaltung benötigt mindestens die Firmware-Version "M3W_3.11".  Während der Umschaltung pausiert die Ladung für zwei Minuten.
 9 |     en: Phase switching requires at least firmware version "M3W_3.11." Charging pauses for two minutes during the phase switching.
10 | capabilities: ["1p3p", "mA"]
11 | params:
12 |   - name: host
13 |   - name: port
14 |     default: 502
15 | render: |
16 |   type: daheimladen
17 |   uri: {{ .host }}:{{ .port }}
18 |   phases1p3p: true
19 | 


--------------------------------------------------------------------------------
/templates/definition/charger/delta.yaml:
--------------------------------------------------------------------------------
 1 | template: delta
 2 | products:
 3 |   - brand: Delta
 4 |     description:
 5 |       generic: AC Max Basic
 6 |   - brand: Delta
 7 |     description:
 8 |       generic: AC MAX Smart
 9 |   - brand: Delta
10 |     description:
11 |       generic: SLIM Charger
12 |   - brand: Delta
13 |     description:
14 |       generic: Ultra Fast Charger
15 | capabilities: ["mA", "rfid"]
16 | requirements:
17 |   evcc: ["sponsorship"]
18 | params:
19 |   - name: modbus
20 |     choice: ["rs485", "tcpip"]
21 |     baudrate: 115200
22 |   - name: connector
23 | render: |
24 |   type: delta
25 |   {{- include "modbus" . }}
26 |   connector: {{ .connector }}
27 | 


--------------------------------------------------------------------------------
/templates/definition/charger/eebus.yaml:
--------------------------------------------------------------------------------
 1 | template: eebus
 2 | products:
 3 |   - description:
 4 |       de: EEBUS kompatibel
 5 |       en: EEBUS compatible
 6 | group: generic
 7 | capabilities: ["mA"]
 8 | requirements:
 9 |   evcc: ["eebus"]
10 | params:
11 |   - preset: eebus
12 | render: |
13 |   {{ include "eebus" . }}
14 |   meter: true
15 | 


--------------------------------------------------------------------------------
/templates/definition/charger/em2go-duo.yaml:
--------------------------------------------------------------------------------
 1 | template: em2go-duo
 2 | products:
 3 |   - brand: EM2GO
 4 |     description:
 5 |       generic: Duo Power
 6 | params:
 7 |   - name: modbus
 8 |     choice: ["tcpip"]
 9 |     id: 255
10 |   - name: connector
11 |     default: 1
12 | render: |
13 |   type: em2go-duo
14 |   {{- include "modbus" . }}
15 |   connector: {{ .connector }}
16 | 


--------------------------------------------------------------------------------
/templates/definition/charger/em2go-home.yaml:
--------------------------------------------------------------------------------
 1 | template: em2go-home
 2 | products:
 3 |   - brand: EM2GO
 4 |     description:
 5 |       generic: Home
 6 | capabilities: ["1p3p", "mA"]
 7 | requirements:
 8 |   description:
 9 |     de: "Benötigt FW version >= E3C_V1.1. mA Regelung benötigt FW version >= E3C_V1.3."
10 |     en: "Requires FW Version >= E3C_V1.1. mA regulation requires FW version >= E3C_V1.3."
11 | params:
12 |   - name: host
13 | render: |
14 |   type: em2go-home
15 |   uri: {{ .host }}
16 | 


--------------------------------------------------------------------------------
/templates/definition/charger/em2go.yaml:
--------------------------------------------------------------------------------
 1 | template: em2go
 2 | products:
 3 |   - brand: EM2GO
 4 |     description:
 5 |       generic: Pro Power (OCPP/ONC)
 6 | capabilities: ["mA"]
 7 | requirements:
 8 |   description:
 9 |     de: "Aktuelle Firmware mit Modbus-Unterstützung notwendig (Pro Power: 1.01 bzw. OCPP/ONC: 3.15)"
10 |     en: "Recent firmware with Modbus support required (Pro Power: 1.01 and OCPP/ONC: 3.15)"
11 | params:
12 |   - name: modbus
13 |     choice: ["tcpip"]
14 |     id: 255
15 | render: |
16 |   type: em2go
17 |   {{- include "modbus" . }}
18 | 


--------------------------------------------------------------------------------
/templates/definition/charger/eprowallbox.yaml:
--------------------------------------------------------------------------------
 1 | template: eprowallbox
 2 | products:
 3 |   - brand: Free2Move
 4 |     description:
 5 |       generic: eProWallbox
 6 |   - brand: Free2Move
 7 |     description:
 8 |       generic: eProWallbox Move
 9 | capabilities: ["mA"]
10 | requirements:
11 |   evcc: ["sponsorship"]
12 | params:
13 |   - name: modbus
14 |     choice: ["rs485"]
15 | render: |
16 |   type: eprowallbox
17 |   {{- include "modbus" . }}
18 | 


--------------------------------------------------------------------------------
/templates/definition/charger/etrel-duo.yaml:
--------------------------------------------------------------------------------
 1 | template: etrel-duo
 2 | products:
 3 |   - brand: Etrel
 4 |     description:
 5 |       generic: INCH Duo
 6 | capabilities: ["mA"]
 7 | requirements:
 8 |   evcc: ["sponsorship"]
 9 |   description:
10 |     de: Die Wallbox muss sich im "Power" Modus befinden.
11 |     en: The charger must be switched to "Power" charging mode.
12 | params:
13 |   - name: connector
14 |   - name: host
15 |   - name: port
16 |     default: 502
17 | render: |
18 |   type: etrel
19 |   connector: {{ .connector }}
20 |   uri: {{ .host }}:{{ .port }}
21 | 


--------------------------------------------------------------------------------
/templates/definition/charger/etrel.yaml:
--------------------------------------------------------------------------------
 1 | template: etrel
 2 | products:
 3 |   - brand: Etrel
 4 |     description:
 5 |       generic: INCH
 6 |   - brand: Sonnen
 7 |     description:
 8 |       generic: sonnenCharger
 9 | capabilities: ["mA"]
10 | requirements:
11 |   evcc: ["sponsorship"]
12 |   description:
13 |     de: Die Wallbox muss sich im "Power" Modus befinden.
14 |     en: The charger must be switched to "Power" charging mode.
15 | params:
16 |   - name: host
17 |   - name: port
18 |     default: 502
19 | render: |
20 |   type: etrel
21 |   uri: {{ .host }}:{{ .port }}
22 | 


--------------------------------------------------------------------------------
/templates/definition/charger/evse-din.yaml:
--------------------------------------------------------------------------------
 1 | template: evse-din
 2 | covers:
 3 |   - evse_din
 4 | products:
 5 |   - brand: Stark in Strom
 6 |     description:
 7 |       generic: Easy
 8 |   - description:
 9 |       generic: EVSE DIN
10 | params:
11 |   - name: modbus
12 |     choice: ["rs485"]
13 |     baudrate: 9600
14 |     comset: 8N1
15 | render: |
16 |   type: evsedin
17 |   {{- include "modbus" . }}
18 | 


--------------------------------------------------------------------------------
/templates/definition/charger/evsewifi.yaml:
--------------------------------------------------------------------------------
 1 | template: evsewifi
 2 | products:
 3 |   - description:
 4 |       generic: EVSE-WiFi
 5 | params:
 6 |   - name: host
 7 | render: |
 8 |   type: evsewifi
 9 |   uri: http://{{ .host }}
10 | 


--------------------------------------------------------------------------------
/templates/definition/charger/fronius-wattpilot.yaml:
--------------------------------------------------------------------------------
 1 | template: fronius-wattpilot
 2 | deprecated: true
 3 | products:
 4 |   - brand: Fronius
 5 |     description:
 6 |       generic: Wattpilot
 7 | capabilities: ["1p3p", "rfid"]
 8 | requirements:
 9 |   description:
10 |     de: |
11 |       Benötigt mindestens Firmware 36.3 oder neuer.
12 |     en: |
13 |       Requires firmware 36.3 or later.
14 | params:
15 |   - name: host
16 |   - name: password
17 |     mask: true
18 | render: |
19 |   type: wattpilot
20 |   uri: {{ .host }}
21 |   password: {{ .password }}
22 | 


--------------------------------------------------------------------------------
/templates/definition/charger/go-e.yaml:
--------------------------------------------------------------------------------
 1 | template: go-e
 2 | products:
 3 |   - brand: go-e
 4 |     description:
 5 |       generic: Charger HOMEfix
 6 |   - brand: go-e
 7 |     description:
 8 |       generic: Charger PRO
 9 | capabilities: ["rfid"]
10 | requirements:
11 |   description:
12 |     en: Requires firmware 040.0 or later. HTTP API v1 or v2 must be activated.
13 |     de: Benötigt mindestens Firmware 040.0 oder neuer. Das HTTP API v1 oder v2 muss aktiviert sein.
14 |   evcc: ["sponsorship"]
15 | params:
16 |   - name: host
17 | render: |
18 |   type: go-e
19 |   uri: http://{{ .host }}
20 | 


--------------------------------------------------------------------------------
/templates/definition/charger/hardybarth-ecb1.yaml:
--------------------------------------------------------------------------------
 1 | template: hardybarth-ecb1
 2 | products:
 3 |   - brand: Hardy Barth
 4 |     description:
 5 |       generic: cPH1
 6 |   - brand: echarge
 7 |     description:
 8 |       generic: cPH1
 9 | requirements:
10 |   evcc: ["sponsorship"]
11 |   description:
12 |     de: Als Betriebsmodus muss `manual` ausgewählt sein
13 |     en: Charge mode must be configured as `manual`
14 | params:
15 |   - name: host
16 |   - name: connector
17 |     default: 1
18 |     advanced: true
19 | render: |
20 |   type: hardybarth-ecb1
21 |   uri: http://{{ .host }}
22 |   chargecontrol: {{ .connector }}
23 |   meter: {{ .connector }}
24 | 


--------------------------------------------------------------------------------
/templates/definition/charger/hesotec.yaml:
--------------------------------------------------------------------------------
 1 | template: hesotec
 2 | products:
 3 |   - brand: Hesotec
 4 |     description:
 5 |       generic: eSat
 6 |   - brand: Hesotec
 7 |     description:
 8 |       generic: eBox
 9 | requirements:
10 |   evcc: ["sponsorship"]
11 | params:
12 |   - name: modbus
13 |     choice: ["tcpip"]
14 | render: |
15 |   type: hesotec
16 |   {{- include "modbus" . }}
17 | 


--------------------------------------------------------------------------------
/templates/definition/charger/homewizard.yaml:
--------------------------------------------------------------------------------
 1 | template: homewizard
 2 | products:
 3 |   - brand: HomeWizard
 4 | group: switchsockets
 5 | params:
 6 |   - name: host
 7 |   - preset: switchsocket
 8 | render: |
 9 |   type: homewizard
10 |   uri: http://{{ .host }}
11 | 


--------------------------------------------------------------------------------
/templates/definition/charger/innogy-ebox.yaml:
--------------------------------------------------------------------------------
 1 | template: innogy-ebox
 2 | products:
 3 |   - brand: Innogy
 4 |     description:
 5 |       generic: eBox
 6 |   - brand: E.ON Drive
 7 |     description:
 8 |       generic: eBox
 9 |   - brand: Compleo
10 |     description:
11 |       generic: eBox
12 | capabilities: ["mA"]
13 | requirements:
14 |   evcc: ["sponsorship"]
15 | params:
16 |   - name: modbus
17 |     choice: ["tcpip"]
18 | render: |
19 |   type: innogy
20 |   {{- include "modbus" . }}
21 | 


--------------------------------------------------------------------------------
/templates/definition/charger/kse.yaml:
--------------------------------------------------------------------------------
 1 | template: kse
 2 | products:
 3 |   - brand: KSE
 4 |     description:
 5 |       generic: wBX16
 6 | capabilities: ["rfid", "1p3p"]
 7 | requirements:
 8 |   evcc: ["sponsorship"]
 9 | params:
10 |   - name: modbus
11 |     choice: ["rs485"]
12 |     baudrate: 9600
13 |     comset: 8E1
14 |     id: 100
15 | render: |
16 |   type: kse
17 |   {{- include "modbus" . }}
18 | 


--------------------------------------------------------------------------------
/templates/definition/charger/mennekes-hcc3.yaml:
--------------------------------------------------------------------------------
 1 | template: mennekes-hcc3
 2 | covers: ["amtron", "menneckes-hcc3"]
 3 | products:
 4 |   - brand: Mennekes
 5 |     description:
 6 |       generic: AMTRON Xtra
 7 |   - brand: Mennekes
 8 |     description:
 9 |       generic: AMTRON Premium
10 | requirements:
11 |   evcc: ["sponsorship"]
12 | params:
13 |   - name: modbus
14 |     choice: ["tcpip"]
15 |     id: 255
16 | render: |
17 |   type: mennekes-hcc3
18 |   {{- include "modbus" . }}
19 | 


--------------------------------------------------------------------------------
/templates/definition/charger/mystrom.yaml:
--------------------------------------------------------------------------------
 1 | template: mystrom
 2 | products:
 3 |   - brand: myStrom
 4 |     description:
 5 |       generic: Switch
 6 | group: switchsockets
 7 | params:
 8 |   - name: host
 9 |   - preset: switchsocket
10 | render: |
11 |   type: mystrom
12 |   uri: http://{{ .host }}
13 |   {{ include "switchsocket" . }}
14 | 


--------------------------------------------------------------------------------
/templates/definition/charger/neoom-n-plus.yaml:
--------------------------------------------------------------------------------
 1 | template: neoom-n-plus
 2 | products:
 3 |   - brand: Neoom
 4 |     description:
 5 |       generic: N+
 6 | capabilities: ["mA", "1p3p"]
 7 | requirements:
 8 |   evcc: ["sponsorship"]
 9 | params:
10 |   - name: modbus
11 |     choice: ["tcpip"]
12 | render: |
13 |   type: compleo
14 |   {{- include "modbus" . }}
15 | 


--------------------------------------------------------------------------------
/templates/definition/charger/neoom-n.yaml:
--------------------------------------------------------------------------------
 1 | template: neoom-n
 2 | products:
 3 |   - brand: Neoom
 4 |     description:
 5 |       generic: N
 6 | capabilities: ["mA", "1p3p"]
 7 | requirements:
 8 |   evcc: ["sponsorship"]
 9 | params:
10 |   - name: modbus
11 |     choice: ["tcpip"]
12 | render: |
13 |   type: compleo
14 |   {{- include "modbus" . }}
15 | 


--------------------------------------------------------------------------------
/templates/definition/charger/nrgkick-bluetooth.yaml:
--------------------------------------------------------------------------------
 1 | template: nrgkick-bluetooth
 2 | deprecated: true
 3 | products:
 4 |   - brand: NRGkick
 5 |     description:
 6 |       generic: Bluetooth
 7 | requirements:
 8 |   description:
 9 |     de: NRGkick Ladeeinheit via Bluetooth (älter als 2022/2023)
10 |     en: NRGkick charging unit via Bluetooth (older than 2022/2023)
11 | params:
12 |   - name: mac
13 |     required: true
14 |   - name: pin
15 |     required: true
16 |     mask: true
17 | render: |
18 |   type: nrgkick-bluetooth
19 |   mac: {{ .mac }}
20 |   pin: {{ .pin }}
21 | 


--------------------------------------------------------------------------------
/templates/definition/charger/nrgkick-connect.yaml:
--------------------------------------------------------------------------------
 1 | template: nrgkick-connect
 2 | products:
 3 |   - brand: NRGkick
 4 |     description:
 5 |       generic: Connect
 6 | requirements:
 7 |   description:
 8 |     de: NRGkick Ladeeinheit via HTTP (älter als 2022/2023)
 9 |     en: NRGkick charging unit via HTTP (older than 2022/2023)
10 | params:
11 |   - name: host
12 |   - name: mac
13 |     required: true
14 |   - name: password
15 |     required: true
16 | render: |
17 |   type: nrgkick-connect
18 |   uri: http://{{ .host }}
19 |   mac: {{ .mac }} # BT device MAC address (sudo hcitool lescan)
20 |   password: {{ .password }}
21 | 


--------------------------------------------------------------------------------
/templates/definition/charger/obo.yaml:
--------------------------------------------------------------------------------
 1 | template: obo
 2 | products:
 3 |   - brand: EcoHarmony
 4 |     description:
 5 |       generic: EVSE EPC 2.0 Plus
 6 |   - brand: OBO Bettermann
 7 |     description:
 8 |       generic: Ion
 9 |   - brand: Viridian EV
10 |     description:
11 |       generic: EVSE EPC 2.0 Plus
12 | params:
13 |   - name: modbus
14 |     choice: ["rs485", "tcpip"]
15 |     baudrate: 19200
16 |     comset: 8E1
17 |     id: 101
18 | render: |
19 |   type: obo
20 |   {{- include "modbus" . }}
21 | 


--------------------------------------------------------------------------------
/templates/definition/charger/ocpp-abb-tac.yaml:
--------------------------------------------------------------------------------
 1 | template: ocpp-abb-tac
 2 | covers: ["ocpp-abb"]
 3 | products:
 4 |   - brand: ABB
 5 |     description:
 6 |       generic: Terra AC (OCPP)
 7 | capabilities: ["mA", "rfid"]
 8 | requirements:
 9 |   evcc: ["sponsorship", "skiptest"]
10 |   description:
11 |     generic: https://library.e.abb.com/public/8f07987a3a284da6bf4e4f8f53cd6502/ABB_Terra_AC_Charger_OCPP1.6_ImplementationOverview%20_v1.8_FW1.6.6.pdf
12 | params:
13 |   - preset: ocpp
14 | render: |
15 |   {{ include "ocpp" . }}
16 |   stacklevelzero: true
17 | 


--------------------------------------------------------------------------------
/templates/definition/charger/ocpp-abl.yaml:
--------------------------------------------------------------------------------
 1 | template: ocpp-abl
 2 | products:
 3 |   - brand: ABL
 4 |     description:
 5 |       generic: eMH2 (OCPP)
 6 |   - brand: ABL
 7 |     description:
 8 |       generic: eMH3 (OCPP)
 9 |   - brand: ABL
10 |     description:
11 |       generic: eM4 Single (OCPP)
12 |   - brand: ABL
13 |     description:
14 |       generic: eM4 Twin (OCPP)
15 | capabilities: ["mA", "rfid"]
16 | requirements:
17 |   evcc: ["sponsorship", "skiptest"]
18 | params:
19 |   - preset: ocpp
20 | render: |
21 |   {{ include "ocpp" . }}
22 | 


--------------------------------------------------------------------------------
/templates/definition/charger/ocpp-alfen.yaml:
--------------------------------------------------------------------------------
 1 | template: ocpp-alfen
 2 | products:
 3 |   - brand: Alfen
 4 |     description:
 5 |       generic: Eve (OCPP)
 6 | capabilities: ["mA", "rfid", "1p3p"]
 7 | requirements:
 8 |   evcc: ["sponsorship", "skiptest"]
 9 | params:
10 |   - preset: ocpp
11 | render: |
12 |   {{ include "ocpp" . }}
13 | 


--------------------------------------------------------------------------------
/templates/definition/charger/ocpp-autoaid.yaml:
--------------------------------------------------------------------------------
 1 | template: ocpp-autoaid
 2 | products:
 3 |   - brand: Autoaid
 4 |     description:
 5 |       generic: Intelligent Wallbox
 6 |   - brand: Autoaid
 7 |     description:
 8 |       generic: Business Wallbox
 9 | capabilities: ["rfid"]
10 | requirements:
11 |   evcc: ["sponsorship", "skiptest"]
12 | params:
13 |   - preset: ocpp
14 | render: |
15 |   {{ include "ocpp" . }}
16 | 


--------------------------------------------------------------------------------
/templates/definition/charger/ocpp-beny.yaml:
--------------------------------------------------------------------------------
 1 | template: ocpp-beny
 2 | products:
 3 |   - brand: ZJ Beny
 4 |     description:
 5 |       generic: BCP EV charger
 6 | capabilities: ["rfid"]
 7 | requirements:
 8 |   evcc: ["sponsorship", "skiptest"]
 9 | params:
10 |   - preset: ocpp
11 | render: |
12 |   {{ include "ocpp" . }}
13 | 


--------------------------------------------------------------------------------
/templates/definition/charger/ocpp-chargeamps.yaml:
--------------------------------------------------------------------------------
 1 | template: ocpp-chargeamps
 2 | products:
 3 |   - brand: Charge Amps
 4 |     description:
 5 |       generic: Halo
 6 | capabilities: ["rfid"]
 7 | requirements:
 8 |   evcc: ["sponsorship", "skiptest"]
 9 | params:
10 |   - preset: ocpp
11 | render: |
12 |   {{ include "ocpp" . }}
13 | 


--------------------------------------------------------------------------------
/templates/definition/charger/ocpp-elecq.yaml:
--------------------------------------------------------------------------------
 1 | template: ocpp-elecq
 2 | products:
 3 |   - brand: Elecq
 4 |     description:
 5 |       generic: Home
 6 |   - brand: Elecq
 7 |     description:
 8 |       generic: Biz
 9 |   - brand: Elecq
10 |     description:
11 |       generic: Station
12 | requirements:
13 |   evcc: ["sponsorship", "skiptest"]
14 | params:
15 |   - preset: ocpp
16 | render: |
17 |   {{ include "ocpp" . }}
18 | 


--------------------------------------------------------------------------------
/templates/definition/charger/ocpp-enercab.yaml:
--------------------------------------------------------------------------------
 1 | template: ocpp-enercab
 2 | products:
 3 |   - brand: enercab
 4 |     description:
 5 |       generic: smart
 6 |   - brand: eledio
 7 |     description:
 8 |       generic: go
 9 | capabilities: ["1p3p"]
10 | requirements:
11 |   description:
12 |     generic: |
13 |       https://www.enercab.at/index.php?controller=attachment&id_attachment=311
14 |   evcc: ["sponsorship", "skiptest"]
15 | params:
16 |   - preset: ocpp
17 | render: |
18 |   {{ include "ocpp" . }}
19 | 


--------------------------------------------------------------------------------
/templates/definition/charger/ocpp-enplus.yaml:
--------------------------------------------------------------------------------
 1 | template: ocpp-enplus
 2 | products:
 3 |   - brand: EN+
 4 |     description:
 5 |       generic: AC EV Charger
 6 | capabilities: ["rfid"]
 7 | requirements:
 8 |   evcc: ["sponsorship", "skiptest"]
 9 | params:
10 |   - preset: ocpp
11 | render: |
12 |   {{ include "ocpp" . }}
13 | 


--------------------------------------------------------------------------------
/templates/definition/charger/ocpp-entratek.yaml:
--------------------------------------------------------------------------------
 1 | template: ocpp-entratek
 2 | products:
 3 |   - brand: EntraTek
 4 |     description:
 5 |       generic: Power Dot Fix
 6 |   - brand: EntraTek
 7 |     description:
 8 |       generic: Power Dot Pro 2
 9 | capabilities: ["rfid"]
10 | requirements:
11 |   evcc: ["sponsorship", "skiptest"]
12 | params:
13 |   - preset: ocpp
14 | render: |
15 |   {{ include "ocpp" . }}
16 | 


--------------------------------------------------------------------------------
/templates/definition/charger/ocpp-esolutions.yaml:
--------------------------------------------------------------------------------
 1 | template: ocpp-esolutions
 2 | products:
 3 |   - brand: Free2move eSolutions
 4 |     description:
 5 |       generic: eProWallbox
 6 | capabilities: ["rfid"]
 7 | requirements:
 8 |   evcc: ["sponsorship", "skiptest"]
 9 | params:
10 |   - preset: ocpp
11 | render: |
12 |   {{ include "ocpp" . }}
13 | 


--------------------------------------------------------------------------------
/templates/definition/charger/ocpp-evbox-elvi.yaml:
--------------------------------------------------------------------------------
 1 | template: ocpp-evbox-elvi
 2 | covers: ["elvi"]
 3 | products:
 4 |   - brand: EVBox
 5 |     description:
 6 |       generic: Elvi
 7 | requirements:
 8 |   evcc: ["sponsorship", "skiptest"]
 9 | params:
10 |   - preset: ocpp
11 |   - name: meter
12 |     type: bool
13 |     default: true
14 |   - name: meterinterval
15 |     deprecated: true
16 | render: |
17 |   {{ include "ocpp" . }}
18 |   {{- if eq .meter "false" }}
19 |   metervalues: Current.Offered
20 |   {{- end }}
21 | 


--------------------------------------------------------------------------------
/templates/definition/charger/ocpp-goe.yaml:
--------------------------------------------------------------------------------
 1 | template: ocpp-goe
 2 | covers: ["ocpp-fronius-wattpilot"]
 3 | products:
 4 |   - brand: go-e
 5 |     description:
 6 |       generic: Charger V3 (OCPP)
 7 |   - brand: go-e
 8 |     description:
 9 |       generic: Charger Gemini (OCPP)
10 |   - brand: go-e
11 |     description:
12 |       generic: Charger PRO (OCPP)
13 |   - brand: Fronius
14 |     description:
15 |       generic: Wattpilot (OCPP)
16 | capabilities: ["rfid", "1p3p"]
17 | requirements:
18 |   evcc: ["sponsorship", "skiptest"]
19 | params:
20 |   - preset: ocpp
21 | render: |
22 |   {{ include "ocpp" . }}
23 | 


--------------------------------------------------------------------------------
/templates/definition/charger/ocpp-huawei.yaml:
--------------------------------------------------------------------------------
 1 | template: ocpp-huawei
 2 | products:
 3 |   - brand: Huawei
 4 |     description:
 5 |       generic: SCharger-7KS-S0
 6 |   - brand: Huawei
 7 |     description:
 8 |       generic: SCharger-22KT-S0
 9 | requirements:
10 |   evcc: ["sponsorship", "skiptest"]
11 | params:
12 |   - preset: ocpp
13 | render: |
14 |   {{ include "ocpp" . }}
15 |   forcepowerctrl: true
16 | 


--------------------------------------------------------------------------------
/templates/definition/charger/ocpp-orbis.yaml:
--------------------------------------------------------------------------------
 1 | template: ocpp-orbis
 2 | covers: ["orbis-viaris"]
 3 | products:
 4 |   - brand: Orbis
 5 |     description:
 6 |       generic: Viaris
 7 | requirements:
 8 |   evcc: ["sponsorship", "skiptest"]
 9 | params:
10 |   - preset: ocpp
11 | render: |
12 |   {{ include "ocpp" . }}
13 | 


--------------------------------------------------------------------------------
/templates/definition/charger/ocpp-sungrow.yaml:
--------------------------------------------------------------------------------
 1 | template: ocpp-sungrow
 2 | products:
 3 |   - brand: Sungrow
 4 |     description:
 5 |       generic: AC011E
 6 | capabilities: ["mA", "rfid"]
 7 | requirements:
 8 |   evcc: ["sponsorship", "skiptest"]
 9 | params:
10 |   - preset: ocpp
11 | render: |
12 |   {{ include "ocpp" . }}
13 | 


--------------------------------------------------------------------------------
/templates/definition/charger/ocpp-zaptec.yaml:
--------------------------------------------------------------------------------
 1 | template: ocpp-zaptec
 2 | products:
 3 |   - brand: Zaptec
 4 |     description:
 5 |       generic: Go (OCPP)
 6 | capabilities: ["rfid"]
 7 | requirements:
 8 |   description:
 9 |     generic: |
10 |       OCPP Native mode
11 | 
12 |       https://help.zaptec.com/hc/en-001/articles/22330328601489-Zaptec-Go-OCPP-Native-configuration-guide#h_01HP261F5NP6Z9VY0MVHJCZEBJ
13 |   evcc: ["sponsorship", "skiptest"]
14 | params:
15 |   - preset: ocpp
16 | render: |
17 |   {{ include "ocpp" . }}
18 | 


--------------------------------------------------------------------------------
/templates/definition/charger/openevse.yaml:
--------------------------------------------------------------------------------
 1 | template: openevse
 2 | products:
 3 |   - brand: OpenEVSE
 4 | requirements:
 5 |   description:
 6 |     en: Requires firmware 7.0 or later.
 7 |     de: Benötigt mindestens Firmware 7.0 oder neuer.
 8 | params:
 9 |   - name: host
10 |   - name: user
11 |   - name: password
12 |     mask: true
13 | render: |
14 |   type: openevse
15 |   uri: http://{{ .host }}
16 |   user: {{ .user }}
17 |   password: {{ .password }}
18 | 


--------------------------------------------------------------------------------
/templates/definition/charger/openwb-pro.yaml:
--------------------------------------------------------------------------------
 1 | template: openwb-pro
 2 | products:
 3 |   - brand: openWB
 4 |     description:
 5 |       generic: Pro
 6 | capabilities: ["1p3p", "mA", "iso151182"]
 7 | params:
 8 |   - name: host
 9 | render: |
10 |   type: openwbpro
11 |   uri: http://{{ .host }}
12 | 


--------------------------------------------------------------------------------
/templates/definition/charger/pantabox.yaml:
--------------------------------------------------------------------------------
 1 | template: pantabox
 2 | products:
 3 |   - brand: INRO
 4 |     description:
 5 |       generic: Pantabox
 6 | params:
 7 |   - name: host
 8 | render: |
 9 |   type: pantabox
10 |   uri: http://{{ .host }}
11 | 


--------------------------------------------------------------------------------
/templates/definition/charger/pcelectric-garo.yaml:
--------------------------------------------------------------------------------
 1 | template: pcelectric-garo
 2 | products:
 3 |   - brand: PC Electric
 4 |     description:
 5 |       generic: Garo
 6 | requirements:
 7 |   evcc: ["sponsorship"]
 8 |   description:
 9 |     de: Es können momentan nur als Master konfigurierte Geräte verwendet werden!
10 |     en: Only devices configured as master can be used right now!
11 | params:
12 |   - name: host
13 |   - name: port
14 |     default: 8080
15 | render: |
16 |   type: garo
17 |   uri: http://{{ .host }}:{{ .port }}/servlet
18 | 


--------------------------------------------------------------------------------
/templates/definition/charger/phoenix-charx.yaml:
--------------------------------------------------------------------------------
 1 | template: phoenix-charx
 2 | products:
 3 |   - brand: Phoenix Contact
 4 |     description:
 5 |       generic: CHARX
 6 |   - brand: LadeFoxx
 7 |     description:
 8 |       generic: EvLoad
 9 |   - brand: LadeFoxx
10 |     description:
11 |       generic: Mikro 2.0
12 |   - brand: Veton
13 |     description:
14 |       generic: One
15 |   - brand: Veton
16 |     description:
17 |       generic: Two
18 |   - brand: Veton
19 |     description:
20 |       generic: Wall
21 | params:
22 |   - name: modbus
23 |     choice: ["tcpip"]
24 |     id: 255
25 |   - name: connector
26 | render: |
27 |   type: phoenix-charx
28 |   {{- include "modbus" . }}
29 |   connector: {{ .connector }}
30 | 


--------------------------------------------------------------------------------
/templates/definition/charger/phoenix-em-eth.yaml:
--------------------------------------------------------------------------------
 1 | template: phoenix-em-eth
 2 | products:
 3 |   - brand: Phoenix Contact
 4 |     description:
 5 |       generic: EM-CP-PP-ETH
 6 | params:
 7 |   - name: modbus
 8 |     choice: ["tcpip"]
 9 |     id: 180
10 | render: |
11 |   type: phoenix-em-eth
12 |   {{- include "modbus" . }}
13 | 


--------------------------------------------------------------------------------
/templates/definition/charger/phoenix-ev-ser.yaml:
--------------------------------------------------------------------------------
 1 | template: phoenix-ev-ser
 2 | products:
 3 |   - brand: Phoenix Contact
 4 |     description:
 5 |       generic: EV-SER
 6 | params:
 7 |   - name: modbus
 8 |     choice: ["rs485"]
 9 | render: |
10 |   type: phoenix-ev-ser
11 |   {{- include "modbus" . }}
12 | 


--------------------------------------------------------------------------------
/templates/definition/charger/porsche-pmcc.yaml:
--------------------------------------------------------------------------------
 1 | template: pmcc
 2 | products:
 3 |   - brand: Porsche
 4 |     description:
 5 |       generic: Mobile Charger Connect
 6 | capabilities: ["iso151182", "mA"]
 7 | requirements:
 8 |   evcc: ["eebus"]
 9 | params:
10 |   - preset: eebus
11 | render: |
12 |   {{ include "eebus" . }}
13 |   meter: true
14 |   vasvw: true
15 | 


--------------------------------------------------------------------------------
/templates/definition/charger/porsche-pmcp.yaml:
--------------------------------------------------------------------------------
 1 | template: pmcp
 2 | products:
 3 |   - brand: Porsche
 4 |     description:
 5 |       generic: Mobile Charger Plus
 6 | requirements:
 7 |   evcc: ["eebus"]
 8 | params:
 9 |   - preset: eebus
10 | render: |
11 |   {{ include "eebus" . }}
12 |   meter: true
13 | 


--------------------------------------------------------------------------------
/templates/definition/charger/pracht-alpha.yaml:
--------------------------------------------------------------------------------
 1 | template: pracht-alpha
 2 | products:
 3 |   - brand: Pracht
 4 |     description:
 5 |       generic: Alpha XT
 6 |   - brand: Pracht
 7 |     description:
 8 |       generic: XT+
 9 |   - brand: Pracht
10 |     description:
11 |       generic: Mono XT
12 |   - brand: Pracht
13 |     description:
14 |       generic: PNI
15 | requirements:
16 |   evcc: ["sponsorship"]
17 | params:
18 |   - name: modbus
19 |     choice: ["rs485", "tcpip"]
20 |     baudrate: 9600
21 |     comset: 8N1
22 |     id: 1
23 |   - name: connector
24 |   - name: timeout
25 | render: |
26 |   type: pracht-alpha
27 |   {{- include "modbus" . }}
28 |   connector: {{ .connector }}
29 |   timeout: {{ .timeout }}
30 | 


--------------------------------------------------------------------------------
/templates/definition/charger/pulsares.yaml:
--------------------------------------------------------------------------------
 1 | template: pulsares
 2 | products:
 3 |   - brand: Pulsares
 4 |     description:
 5 |       generic: SimpleBox
 6 | params:
 7 |   - name: modbus
 8 |     choice: ["rs485"]
 9 |     baudrate: 9600
10 |     comset: 8N1
11 | render: |
12 |   type: pulsares
13 |   {{- include "modbus" . }}
14 | 


--------------------------------------------------------------------------------
/templates/definition/charger/pulsatrix.yaml:
--------------------------------------------------------------------------------
 1 | template: pulsatrix
 2 | products:
 3 |   - brand: Pulsatrix
 4 | requirements:
 5 |   evcc: ["sponsorship"]
 6 | params:
 7 |   - name: host #IP address or hostname (can be found on 3rd page of SECC display)
 8 |     required: true
 9 |     help:
10 |       en: Shown on 3rd page of SECC display
11 |       de: Wird auf der dritten Displayseite des SECC angezeigt
12 | render: |
13 |   type: pulsatrix
14 |   host: {{ .host }}
15 | 


--------------------------------------------------------------------------------
/templates/definition/charger/scheider-evlink-v3.yaml:
--------------------------------------------------------------------------------
 1 | template: schneider-evlink-v3
 2 | covers: ["schneider-evlink"]
 3 | products:
 4 |   - brand: Schneider
 5 |     description:
 6 |       generic: EVlink Pro
 7 | requirements:
 8 |   evcc: ["sponsorship"]
 9 | params:
10 |   - name: modbus
11 |     choice: ["tcpip"]
12 |     id: 255
13 | render: |
14 |   type: schneider-v3
15 |   {{- include "modbus" . }}
16 | 


--------------------------------------------------------------------------------
/templates/definition/charger/senec-plus.yaml:
--------------------------------------------------------------------------------
 1 | template: senec-plus
 2 | products:
 3 |   - brand: SENEC
 4 |     description:
 5 |       generic: Plus
 6 | capabilities: ["mA", "1p3p"]
 7 | requirements:
 8 |   evcc: ["sponsorship"]
 9 | params:
10 |   - name: modbus
11 |     choice: ["tcpip"]
12 | render: |
13 |   type: compleo
14 |   {{- include "modbus" . }}
15 | 


--------------------------------------------------------------------------------
/templates/definition/charger/senec-premium.yaml:
--------------------------------------------------------------------------------
 1 | template: senec-premium
 2 | products:
 3 |   - brand: SENEC
 4 |     description:
 5 |       generic: Premium
 6 | capabilities: ["mA", "rfid", "1p3p"]
 7 | requirements:
 8 |   evcc: ["sponsorship"]
 9 | params:
10 |   - name: modbus
11 |     choice: ["tcpip"]
12 | render: |
13 |   type: compleo
14 |   {{- include "modbus" . }}
15 | 


--------------------------------------------------------------------------------
/templates/definition/charger/sigenergy.yaml:
--------------------------------------------------------------------------------
 1 | template: sigenergy
 2 | products:
 3 |   - brand: Sigenergy
 4 |     description:
 5 |       generic: EVAC series
 6 | capabilities: ["mA"]
 7 | requirements:
 8 |   evcc: ["sponsorship"]
 9 | params:
10 |   - name: modbus
11 |     choice: ["tcpip"]
12 |     id: 1
13 | render: |
14 |   type: sigenergy
15 |   {{- include "modbus" . }}
16 | 


--------------------------------------------------------------------------------
/templates/definition/charger/smartevse.yaml:
--------------------------------------------------------------------------------
 1 | template: smartevse
 2 | products:
 3 |   - brand: Edgetech
 4 |     description:
 5 |       generic: Smart EVSE
 6 | capabilities: ["1p3p"]
 7 | params:
 8 |   - name: modbus
 9 |     choice: ["rs485"]
10 |     baudrate: 9600
11 |     comset: 8N1
12 |     id: 1
13 | render: |
14 |   type: smartevse
15 |   {{- include "modbus" . }}
16 | 


--------------------------------------------------------------------------------
/templates/definition/charger/smartwb.yaml:
--------------------------------------------------------------------------------
 1 | template: smartwb
 2 | products:
 3 |   - description:
 4 |       generic: smartWB
 5 | params:
 6 |   - name: host
 7 | render: |
 8 |   type: evsewifi
 9 |   uri: http://{{ .host }}
10 |   meter:
11 |     power: true
12 |     energy: true
13 |     currents: true
14 |     voltages: true
15 | 


--------------------------------------------------------------------------------
/templates/definition/charger/solax-g2.yaml:
--------------------------------------------------------------------------------
 1 | template: solax-g2
 2 | products:
 3 |   - brand: Solax
 4 |     description:
 5 |       generic: X3-HAC
 6 | capabilities: ["mA"]
 7 | requirements:
 8 |   evcc: ["sponsorship"]
 9 |   description:
10 |     de: Die Wallbox muss sich im Modus "Schnell" befinden und vom Wechselrichtersystem entkoppelt sein.
11 |     en: The charger must be in “Fast” mode and decoupled from the inverter system.
12 | params:
13 |   - name: modbus
14 |     choice: ["rs485"]
15 |     baudrate: 9600
16 |     comset: 8N1
17 |     id: 70
18 | render: |
19 |   type: solax-g2
20 |   {{- include "modbus" . }}
21 | 


--------------------------------------------------------------------------------
/templates/definition/charger/sungrow.yaml:
--------------------------------------------------------------------------------
 1 | template: sungrow
 2 | products:
 3 |   - brand: Sungrow
 4 |     description:
 5 |       generic: AC011E-01
 6 |   - brand: Sungrow
 7 |     description:
 8 |       generic: AC22E-01
 9 | capabilities: ["mA", "1p3p"]
10 | params:
11 |   - name: modbus
12 |     choice: ["rs485", "tcpip"]
13 |     id: 248
14 | render: |
15 |   type: sungrow
16 |   {{- include "modbus" . }}
17 | 


--------------------------------------------------------------------------------
/templates/definition/charger/tapo.yaml:
--------------------------------------------------------------------------------
 1 | template: tapo
 2 | products:
 3 |   - brand: TP-Link
 4 |     description:
 5 |       generic: Tapo P-Series Smart Plug
 6 | group: switchsockets
 7 | params:
 8 |   - name: host
 9 |   - name: user
10 |     required: true
11 |   - name: password
12 |     required: true
13 |   - preset: switchsocket
14 | render: |
15 |   type: tapo
16 |   uri: http://{{ .host }}
17 |   user: {{ .user }}
18 |   password: {{ .password }}
19 |   {{ include "switchsocket" . }}
20 | 


--------------------------------------------------------------------------------
/templates/definition/charger/tinkerforge-warp3-smart.yaml:
--------------------------------------------------------------------------------
 1 | template: tinkerforge-warp3-smart
 2 | products:
 3 |   - brand: TinkerForge
 4 |     description:
 5 |       generic: WARP3 Charger Smart
 6 | capabilities: ["mA", "1p3p", "rfid"]
 7 | requirements:
 8 |   evcc: ["skiptest"]
 9 | params:
10 |   - preset: mqtt
11 |   - name: topic
12 |     default: warp
13 | render: |
14 |   type: warp2
15 |   {{ include "mqtt" . }}
16 |   topic: {{ .topic }}
17 |   energymanager: {{ .topic }}
18 | 


--------------------------------------------------------------------------------
/templates/definition/charger/tplink.yaml:
--------------------------------------------------------------------------------
 1 | template: tplink
 2 | products:
 3 |   - brand: TP-Link
 4 |     description:
 5 |       generic: H-Series Smart Plug
 6 | group: switchsockets
 7 | params:
 8 |   - name: host
 9 |   - preset: switchsocket
10 | render: |
11 |   type: tplink
12 |   uri: {{ .host }}
13 |   {{ include "switchsocket" . }}
14 | 


--------------------------------------------------------------------------------
/templates/definition/charger/v2c.yaml:
--------------------------------------------------------------------------------
 1 | template: v2c
 2 | covers: ["trydan"]
 3 | products:
 4 |   - brand: V2C
 5 |     description:
 6 |       generic: Trydan
 7 | requirements:
 8 |   evcc: ["sponsorship"]
 9 | params:
10 |   - name: host
11 | render: |
12 |   type: trydan
13 |   uri: http://{{ .host }}
14 | 


--------------------------------------------------------------------------------
/templates/definition/charger/versicharge.yaml:
--------------------------------------------------------------------------------
 1 | template: versicharge
 2 | products:
 3 |   - brand: Siemens
 4 |     description:
 5 |       generic: Versicharge GEN3
 6 | requirements:
 7 |   evcc: ["sponsorship"]
 8 |   description:
 9 |     de: Erfordert Firmware >= 2.135
10 |     en: Requires firmware >= 2.135
11 | params:
12 |   - name: modbus
13 |     choice: ["tcpip"]
14 |     id: 2
15 | render: |
16 |   type: versicharge
17 |   {{- include "modbus" . }}
18 | 


--------------------------------------------------------------------------------
/templates/definition/charger/victron-evcs.yaml:
--------------------------------------------------------------------------------
 1 | template: victron-evcs
 2 | products:
 3 |   - brand: Victron
 4 |     description:
 5 |       generic: EV Charging Station
 6 | requirements:
 7 |   description:
 8 |     en: Enter the host of the charger (not the GX device) and ensure that the charger is in manual mode.
 9 |     de: Trage den Host der Wallbox (nicht des GX-Geräts) ein und stelle sicher, dass die Wallbox sich im Modus "Manual" befindet.
10 | params:
11 |   - name: modbus
12 |     choice: ["tcpip"]
13 |     id: 1
14 | render: |
15 |   type: victron-evcs
16 |   {{- include "modbus" . }}
17 | 


--------------------------------------------------------------------------------
/templates/definition/charger/victron.yaml:
--------------------------------------------------------------------------------
 1 | template: victron
 2 | products:
 3 |   - brand: Victron
 4 |     description:
 5 |       generic: EV Charging Station (via GX)
 6 | requirements:
 7 |   description:
 8 |     en: Enter the host of the GX device (not the charger). The charger has to be in manual mode and Modbus has to be configured for ID 100.
 9 |     de: Trage den Host des GX-Gerätes (nicht der Wallbox) ein. Die Wallbox muss sich im Modus "Manual" befinden und Modbus ID 100 konfiguriert sein.
10 | params:
11 |   - name: modbus
12 |     choice: ["tcpip"]
13 |     id: 100
14 | render: |
15 |   type: victron
16 |   {{- include "modbus" . }}
17 | 


--------------------------------------------------------------------------------
/templates/definition/charger/wallbe-pre2019.yaml:
--------------------------------------------------------------------------------
 1 | template: wallbe-pre2019
 2 | deprecated: true
 3 | products:
 4 |   - brand: Wallbe
 5 |     description:
 6 |       de: Eco (vor ~2019)
 7 |       en: Eco (pre ~2019)
 8 |   - brand: Wallbe
 9 |     description:
10 |       de: Pro (vor ~2019)
11 |       en: Pro (pre ~2019)
12 | requirements:
13 |   description:
14 |     en: DIP switch 10 must be set to 'ON'.
15 |     de: Im Gerät muss der DIP Schalter 10 auf 'ON' gestellt sein.
16 | params:
17 |   - name: host
18 |   - name: port
19 |     default: 502
20 | render: |
21 |   type: wallbe
22 |   uri: {{ .host }}:{{ .port }}
23 |   legacy: true # set only for older Wallbe devices (pre ~2019, old controller firmware)
24 | 


--------------------------------------------------------------------------------
/templates/definition/charger/wallbe.yaml:
--------------------------------------------------------------------------------
 1 | template: wallbe
 2 | deprecated: true
 3 | products:
 4 |   - brand: Wallbe
 5 |     description:
 6 |       generic: Eco
 7 |   - brand: Wallbe
 8 |     description:
 9 |       generic: Pro
10 | requirements:
11 |   description:
12 |     en: The Wallbe must be connected using Ethernet and the DIP switch 10 must be set to 'ON'.
13 |     de: Die Wallbox muss über ein Netzwerkkabel angebunden sein und im Gerät muss der DIP Schalter 10 auf 'ON' gestellt sein.
14 | params:
15 |   - name: host
16 |   - name: port
17 |     default: 502
18 | render: |
19 |   type: wallbe
20 |   uri: {{ .host }}:{{ .port }}
21 | 


--------------------------------------------------------------------------------
/templates/definition/charger/webasto-next.yaml:
--------------------------------------------------------------------------------
 1 | template: webasto-next
 2 | products:
 3 |   - brand: Ampure
 4 |     description:
 5 |       generic: NEXT
 6 |   - brand: Webasto
 7 |     description:
 8 |       generic: NEXT
 9 | capabilities: ["rfid"]
10 | requirements:
11 |   description:
12 |     de: Modus "HEMS activated" muss aktiviert sein. RFID-Tags können durch evcc nur gelesen werden.
13 |     en: Mode "HEMS activated" must be enabled. RFID tags can only be read by evcc.
14 |   evcc: ["sponsorship"]
15 | params:
16 |   - name: host
17 |   - name: port
18 |     default: 502
19 | render: |
20 |   type: webasto-next
21 |   uri: {{ .host }}:{{ .port }}
22 | 


--------------------------------------------------------------------------------
/templates/definition/charger/weidmüller.yaml:
--------------------------------------------------------------------------------
 1 | template: weidmüller
 2 | products:
 3 |   - brand: Weidmüller
 4 |     description:
 5 |       generic: AC Smart
 6 | capabilities: ["1p3p", "rfid"]
 7 | requirements:
 8 |   evcc: ["sponsorship"]
 9 | params:
10 |   - name: host
11 | render: |
12 |   type: weidmüller
13 |   uri: {{ .host }}:502
14 | 


--------------------------------------------------------------------------------
/templates/definition/embed.go:
--------------------------------------------------------------------------------
1 | package definition
2 | 
3 | import "embed"
4 | 
5 | //go:embed charger/*.yaml meter/*.yaml vehicle/*.yaml tariff/*.yaml
6 | var YamlTemplates embed.FS
7 | 


--------------------------------------------------------------------------------
/templates/definition/meter/ac-elwa-2.yaml:
--------------------------------------------------------------------------------
 1 | template: ac-elwa-2
 2 | products:
 3 |   - brand: my-PV
 4 |     description:
 5 |       generic: AC ELWA 2
 6 | params:
 7 |   - name: usage
 8 |     choice: ["aux"]
 9 |   - name: host
10 |   - name: tempsource
11 |     choice: ["1", "2"]
12 |     default: "1"
13 | render: |
14 |   type: custom
15 |   power:
16 |     source: http
17 |     uri: http://{{ .host }}/data.jsn
18 |     jq: .power_elwa2
19 |   soc:
20 |     source: http
21 |     uri: http://{{ .host }}/data.jsn
22 |     jq: .temp{{ .tempsource }}
23 |     scale: 0.1
24 | 


--------------------------------------------------------------------------------
/templates/definition/meter/ac-elwa-e.yaml:
--------------------------------------------------------------------------------
 1 | template: ac-elwa-e
 2 | covers: ["elwa-e"]
 3 | products:
 4 |   - brand: my-PV
 5 |     description:
 6 |       generic: AC ELWA-E
 7 | params:
 8 |   - name: usage
 9 |     choice: ["aux"]
10 |   - name: host
11 | render: |
12 |   type: custom
13 |   power:
14 |     source: http
15 |     uri: http://{{ .host }}/data.jsn
16 |     jq: .power
17 |   soc:
18 |     source: http
19 |     uri: http://{{ .host }}/data.jsn
20 |     jq: .temp1
21 |     scale: 0.1
22 | 


--------------------------------------------------------------------------------
/templates/definition/meter/apsystems-ez1.yaml:
--------------------------------------------------------------------------------
 1 | template: apsystems-ez1
 2 | products:
 3 |   - brand: APsystems
 4 |     description:
 5 |       generic: EZ1
 6 | params:
 7 |   - name: usage
 8 |     choice: ["pv"]
 9 |   - name: host
10 | render: |
11 |   type: custom
12 |   {{- if eq .usage "pv" }}
13 |   power:
14 |     source: http
15 |     uri: http://{{ .host }}:8050/getOutputData
16 |     jq: .data.p1+.data.p2
17 |   energy:
18 |     source: http
19 |     uri: http://{{ .host }}:8050/getOutputData
20 |     jq: .data.te1+.data.te2
21 |   {{- end }}
22 | 


--------------------------------------------------------------------------------
/templates/definition/meter/be-mpm3pm.yaml:
--------------------------------------------------------------------------------
 1 | template: mpm3pm
 2 | products:
 3 |   - brand: Bernecker Engineering
 4 |     description:
 5 |       generic: MPM3PM
 6 | params:
 7 |   - name: usage
 8 |     choice: ["grid", "charge"]
 9 |   - name: modbus
10 |     choice: ["rs485"]
11 | render: |
12 |   type: mbmd
13 |   {{- include "modbus" . }}
14 |   model: MPM
15 |   power: Power
16 |   energy: Import
17 |   currents:
18 |     - CurrentL1
19 |     - CurrentL2
20 |     - CurrentL3
21 |   {{- if eq .usage "grid" }}
22 |   powers:
23 |     - PowerL1
24 |     - PowerL2
25 |     - PowerL3
26 |   {{- end }}
27 |   {{- if eq .usage "charge" }}
28 |   voltages:
29 |     - VoltageL1
30 |     - VoltageL2
31 |     - VoltageL3
32 |   {{- end }}
33 | 


--------------------------------------------------------------------------------
/templates/definition/meter/bosch-bpt.yaml:
--------------------------------------------------------------------------------
 1 | template: bosch-bpt
 2 | # UDP implementation is broken
 3 | # deprecated: true
 4 | products:
 5 |   - brand: Bosch
 6 |     description:
 7 |       generic: BPT-S 5 Hybrid
 8 | requirements:
 9 |   evcc: ["skiptest"]
10 | params:
11 |   - name: usage
12 |     choice: ["grid", "pv", "battery"]
13 |     allinone: true
14 |   - name: uri
15 |   - name: capacity
16 |     advanced: true
17 | render: |
18 |   type: bosch-bpt
19 |   usage: {{ .usage }}
20 |   uri: {{ .uri }}
21 |   capacity: {{ .capacity }} # kWh
22 | 


--------------------------------------------------------------------------------
/templates/definition/meter/cfos.yaml:
--------------------------------------------------------------------------------
 1 | template: cfos
 2 | products:
 3 |   - brand: cFos
 4 |     description:
 5 |       generic: PowerBrain Meter
 6 | requirements:
 7 |   evcc: ["sponsorship"]
 8 | params:
 9 |   - name: usage
10 |     choice: ["charge"]
11 |   - name: modbus
12 |     choice: ["tcpip"]
13 |     port: 4702
14 |     id: 2
15 | render: |
16 |   type: cfos
17 |   {{- include "modbus" . }}
18 | 


--------------------------------------------------------------------------------
/templates/definition/meter/discovergy.yaml:
--------------------------------------------------------------------------------
 1 | template: discovergy
 2 | products:
 3 |   - description:
 4 |       generic: Discovergy
 5 | params:
 6 |   - name: usage
 7 |     choice: ["grid", "pv"]
 8 |   - name: user
 9 |     required: true
10 |   - name: password
11 |     required: true
12 |   - name: meter
13 |     required: true
14 |     example: 1ESY1161229886
15 | render: |
16 |   type: discovergy
17 |   user: {{ .user }}
18 |   password: {{ .password }} # password
19 |   meter: {{ .meter }}
20 |   {{- if eq .usage "pv" }}
21 |   scale: -1
22 |   {{- end }}
23 | 


--------------------------------------------------------------------------------
/templates/definition/meter/dzg.yaml:
--------------------------------------------------------------------------------
 1 | template: dzg
 2 | products:
 3 |   - brand: DZG
 4 |     description:
 5 |       generic: DVH4013
 6 | params:
 7 |   - name: usage
 8 |     choice: ["charge"]
 9 |   - name: modbus
10 |     choice: ["rs485"]
11 | render: |
12 |   type: mbmd
13 |   {{- include "modbus" . }}
14 |   model: dzg
15 |   power: ImportPower
16 |   energy: Import
17 |   currents:
18 |     - CurrentL1
19 |     - CurrentL2
20 |     - CurrentL3
21 |   voltages:
22 |     - VoltageL1
23 |     - VoltageL2
24 |     - VoltageL3
25 | 


--------------------------------------------------------------------------------
/templates/definition/meter/eastron-sdm220_230.yaml:
--------------------------------------------------------------------------------
 1 | template: eastron-sdm220_230
 2 | products:
 3 |   - brand: Eastron
 4 |     description:
 5 |       generic: SDM220/230
 6 |   - brand: Weidmüller
 7 |     description:
 8 |       generic: EM110-RTU-2P
 9 |   - brand: Weidmüller
10 |     description:
11 |       generic: EM111-RTU-2P
12 | params:
13 |   - name: usage
14 |     choice: ["grid", "charge"]
15 |   - name: modbus
16 |     choice: ["rs485"]
17 | render: |
18 |   type: mbmd
19 |   {{- include "modbus" . }}
20 |   model: sdm220
21 |   power: Power
22 |   energy: Import
23 | 


--------------------------------------------------------------------------------
/templates/definition/meter/eastron-sdm72.yaml:
--------------------------------------------------------------------------------
 1 | template: eastron-sdm72
 2 | products:
 3 |   - brand: Eastron
 4 |     description:
 5 |       generic: SDM72D-M
 6 | params:
 7 |   - name: usage
 8 |     choice: ["grid", "charge"]
 9 |   - name: modbus
10 |     choice: ["rs485"]
11 | render: |
12 |   type: mbmd
13 |   {{- include "modbus" . }}
14 |   model: sdm72
15 |   power: Power
16 |   energy: Import
17 | 


--------------------------------------------------------------------------------
/templates/definition/meter/eebus-mgcp.yaml:
--------------------------------------------------------------------------------
 1 | template: eebus-mgcp
 2 | products:
 3 |   - description:
 4 |       de: "EEBus Netzanschlusspunkt"
 5 |       en: "EEBus Grid Connection Point"
 6 | group: generic
 7 | requirements:
 8 |   description:
 9 |     de: EEBus-Messstelle am Netzanschlusspunkt mit dem Use Case MGCP (Monitoring of Grid Connection Point).
10 |     en: EEBus metering device at the grid connection point using use case MGCP (Monitoring of Grid Connection Point).
11 |   evcc: ["eebus"]
12 | params:
13 |   - name: usage
14 |     choice: ["grid"]
15 |   - preset: eebus
16 | render: |
17 |   {{ include "eebus" . }}
18 |   usage: {{ .usage }}
19 | 


--------------------------------------------------------------------------------
/templates/definition/meter/fritzgrid.yaml:
--------------------------------------------------------------------------------
 1 | template: fritzgrid
 2 | products:
 3 |   - brand: "FRITZ!"
 4 |     description:
 5 |       generic: "FRITZ!Smart Energy 250"
 6 | params:
 7 |   - name: usage
 8 |     choice: ["grid"]
 9 |   - name: uri
10 |     default: https://fritz.box
11 |   - name: user
12 |     required: true
13 |   - name: password
14 |     required: true
15 |   - name: ain
16 |     required: true
17 | render: |
18 |   type: fritzdect
19 |   uri: {{ .uri }}
20 |   user: {{ .user }}
21 |   password: {{ .password }}
22 |   ain: {{ .ain }} # switch actor identification number without blanks (see AIN number on switch sticker)
23 | 


--------------------------------------------------------------------------------
/templates/definition/meter/goodwe-wifi.yaml:
--------------------------------------------------------------------------------
 1 | template: goodwe-wifi
 2 | # UDP implementation is broken
 3 | # deprecated: true
 4 | products:
 5 |   - brand: GoodWe
 6 |     description:
 7 |       generic: GoodWe over Wifi
 8 | requirements:
 9 |   evcc: ["skiptest"]
10 | params:
11 |   - name: usage
12 |     choice: ["grid", "pv", "battery"]
13 |     allinone: true
14 |   - name: uri
15 |     description:
16 |       en: IP address or hostname
17 |       de: IP-Adresse des Hostname
18 | render: |
19 |   type: goodwe-wifi
20 |   usage: {{ .usage }}
21 |   uri: {{ .uri }}
22 | 


--------------------------------------------------------------------------------
/templates/definition/meter/homewizard-kwh.yaml:
--------------------------------------------------------------------------------
 1 | template: homewizard-kwh
 2 | products:
 3 |   - brand: HomeWizard
 4 |     description:
 5 |       generic: kWh Meter
 6 | params:
 7 |   - name: usage
 8 |     choice: ["pv", "charge"]
 9 |   - name: host
10 | render: |
11 |   type: homewizard
12 |   uri: http://{{ .host }}
13 |   usage: {{ .usage }}
14 | 


--------------------------------------------------------------------------------
/templates/definition/meter/homewizard-p1.yaml:
--------------------------------------------------------------------------------
 1 | template: homewizard
 2 | products:
 3 |   - brand: HomeWizard
 4 |     description:
 5 |       generic: Wi-Fi P1 Meter
 6 | params:
 7 |   - name: usage
 8 |     choice: ["grid"]
 9 |   - name: host
10 | render: |
11 |   type: homewizard
12 |   uri: http://{{ .host }}
13 |   usage: {{ .usage }}
14 | 


--------------------------------------------------------------------------------
/templates/definition/meter/hoymiles-opendtu.yaml:
--------------------------------------------------------------------------------
 1 | template: hoymiles-opendtu
 2 | products:
 3 |   - brand: Hoymiles
 4 |     description:
 5 |       generic: HM & HMS Series (via OpenDTU)
 6 | params:
 7 |   - name: usage
 8 |     choice: ["pv"]
 9 |   - name: host
10 | render: |
11 |   type: custom
12 |   power:
13 |     source: http
14 |     uri: http://{{ .host }}/api/livedata/status
15 |     jq: .total.Power.v
16 |   energy:
17 |     source: http
18 |     uri: http://{{ .host }}/api/livedata/status
19 |     jq: .total.YieldTotal.v
20 | 


--------------------------------------------------------------------------------
/templates/definition/meter/inepro.yaml:
--------------------------------------------------------------------------------
 1 | template: inepro
 2 | products:
 3 |   - brand: inepro
 4 |     description:
 5 |       generic: PRO380-MOD
 6 | params:
 7 |   - name: usage
 8 |     choice: ["grid", "charge"]
 9 |   - name: modbus
10 |     choice: ["rs485"]
11 | render: |
12 |   type: mbmd
13 |   {{- include "modbus" . }}
14 |   model: inepro
15 |   power: Power
16 |   energy: Import
17 |   currents:
18 |     - CurrentL1
19 |     - CurrentL2
20 |     - CurrentL3
21 |   {{- if eq .usage "grid" }}
22 |   powers:
23 |     - PowerL1
24 |     - PowerL2
25 |     - PowerL3
26 |   {{- end }}
27 |   {{- if eq .usage "charge" }}
28 |   voltages:
29 |     - VoltageL1
30 |     - VoltageL2
31 |     - VoltageL3
32 |   {{- end }}
33 | 


--------------------------------------------------------------------------------
/templates/definition/meter/iometer.yaml:
--------------------------------------------------------------------------------
 1 | template: iometer
 2 | products:
 3 |   - brand: IOmeter
 4 | params:
 5 |   - name: usage
 6 |     choice: ["grid"]
 7 |   - name: host
 8 |     description:
 9 |       de: IP deines IOmeter
10 |       en: IP of your IOmeter
11 | render: |
12 |   type: custom
13 |   power:
14 |     source: http
15 |     uri: http://{{ .host }}/v1/reading
16 |     method: GET
17 |     jq: .meter.reading.registers[] | select(.obis == "01-00:10.07.00*ff") | .value
18 |     cache: 10s
19 |   energy:
20 |     source: http
21 |     uri: http://{{ .host }}/v1/reading
22 |     method: GET
23 |     jq: (.meter.reading.registers[] | select(.obis == "01-00:01.08.00*ff") | .value) / 1000
24 |     cache: 10s
25 | 


--------------------------------------------------------------------------------
/templates/definition/meter/kostal-piko-legacy.yaml:
--------------------------------------------------------------------------------
 1 | template: kostal-piko-legacy
 2 | products:
 3 |   - brand: Kostal
 4 |     description:
 5 |       generic: Piko (legacy)
 6 | params:
 7 |   - name: usage
 8 |     choice: ["pv"]
 9 |   - name: host
10 |   - name: user
11 |     required: true
12 |   - name: password
13 |     required: true
14 | render: |
15 |   type: custom
16 |   power:
17 |   {{- if eq .usage "pv" }}
18 |     source: http
19 |     uri: http://{{ .host }}
20 |     auth:
21 |       type: basic
22 |       user: {{ .user }}
23 |       password: {{ .password }}
24 |     regex: '(?s)aktuell</td>\s+<td[^>]+>\s+(\d+)</td>'
25 |     default: 0
26 |   {{- end }}
27 | 


--------------------------------------------------------------------------------
/templates/definition/meter/mystrom.yaml:
--------------------------------------------------------------------------------
 1 | template: mystrom
 2 | products:
 3 |   - brand: myStrom
 4 |     description:
 5 |       generic: Switch
 6 | group: switchsockets
 7 | params:
 8 |   - name: usage
 9 |     choice: ["pv", "charge"]
10 |   - name: host
11 | render: |
12 |   type: mystrom
13 |   uri: http://{{ .host }}
14 | 


--------------------------------------------------------------------------------
/templates/definition/meter/shelly-pro-3em.yaml:
--------------------------------------------------------------------------------
 1 | template: shelly-pro-3em
 2 | products:
 3 |   - brand: Shelly
 4 |     description:
 5 |       generic: Pro 3 EM
 6 | params:
 7 |   - name: usage
 8 |     choice: ["grid", "pv", "charge"]
 9 |   - name: host
10 |   - name: user
11 |   - name: password
12 | render: |
13 |   type: shelly
14 |   uri: http://{{ .host }}  # shelly device ip address (local)
15 |   {{- if .user }}
16 |   user: {{ .user }}
17 |   {{- end }}
18 |   {{- if .password }}
19 |   password: {{ .password }}
20 |   {{- end }}
21 |   usage: {{ .usage }}
22 |   channel: 0  # shelly device relay channel
23 | 


--------------------------------------------------------------------------------
/templates/definition/meter/sma-energymeter.yaml:
--------------------------------------------------------------------------------
 1 | template: sma-energy-meter
 2 | products:
 3 |   - brand: SMA
 4 |     description:
 5 |       generic: Energy Meter
 6 | params:
 7 |   - name: usage
 8 |     choice: ["grid", "pv"]
 9 |   - name: host
10 |   - name: interface
11 | render: |
12 |   type: sma
13 |   uri: {{ .host }}
14 |   {{- if .interface }}
15 |   interface: {{ .interface }}
16 |   {{- end }}
17 |   {{- if eq .usage "pv" }}
18 |   scale: -1
19 |   {{- end }}
20 | 


--------------------------------------------------------------------------------
/templates/definition/meter/solaranzeige-mqtt.yaml:
--------------------------------------------------------------------------------
 1 | template: solaranzeige
 2 | products:
 3 |   - brand: Solaranzeige
 4 |     description:
 5 |       generic: Solaranzeige
 6 | requirements:
 7 |   evcc: ["skiptest"]
 8 | params:
 9 |   - name: usage
10 |     choice: ["grid", "pv"]
11 |   - preset: mqtt
12 |   - name: topic
13 |     default: solaranzeige/box1
14 | render: |
15 |   type: custom
16 |   power:
17 |     source: mqtt
18 |     {{- include "mqtt" . | indent 2 }}
19 |     {{- if eq .usage "grid" }}
20 |     topic: {{ .topic }}/einspeisung_bezug
21 |     scale: -1
22 |     {{- end }}
23 |     {{- if eq .usage "pv" }}
24 |     topic: {{ .topic }}/pv_leistung
25 |     {{- end }}
26 | 


--------------------------------------------------------------------------------
/templates/definition/meter/solarmax-inverter-smt.yaml:
--------------------------------------------------------------------------------
 1 | template: solarmax-smt
 2 | products:
 3 |   - brand: SolarMax
 4 |     description:
 5 |       generic: SolarMax SMT
 6 | params:
 7 |   - name: usage
 8 |     choice: ["pv"]
 9 |   - name: modbus
10 |     choice: ["tcpip"]
11 |     id: 1
12 | render: |
13 |   type: custom
14 |   power:
15 |     source: modbus
16 |     {{- include "modbus" . | indent 2 }}
17 |     register:
18 |       address: 4151 # PAC
19 |       type: holding
20 |       decode: uint32
21 |     scale: 0.1
22 |   energy:
23 |     source: modbus
24 |     {{- include "modbus" . | indent 2 }}
25 |     register:
26 |       address: 4129 # Total
27 |       type: holding
28 |       decode: uint32
29 | 


--------------------------------------------------------------------------------
/templates/definition/meter/tapo.yaml:
--------------------------------------------------------------------------------
 1 | template: tapo
 2 | products:
 3 |   - brand: TP-Link
 4 |     description:
 5 |       generic: Tapo P-Series Smart Plug
 6 | group: switchsockets
 7 | params:
 8 |   - name: usage
 9 |     choice: ["pv"]
10 |   - name: host
11 |   - name: user
12 |     required: true
13 |   - name: password
14 |     required: true
15 | render: |
16 |   type: tapo
17 |   uri: http://{{ .host }}
18 |   user: {{ .user }}
19 |   password: {{ .password }}
20 | 


--------------------------------------------------------------------------------
/templates/definition/meter/thor.yaml:
--------------------------------------------------------------------------------
 1 | template: thor
 2 | products:
 3 |   - brand: my-PV
 4 |     description:
 5 |       generic: AC•THOR
 6 | params:
 7 |   - name: usage
 8 |     choice: ["aux"]
 9 |   - name: host
10 | render: |
11 |   type: custom
12 |   power:
13 |     source: http
14 |     uri: http://{{ .host }}/data.jsn
15 |     jq: if .power_act == null then 0 else .power_act end + if .power_ac9 == null then 0 else .power_ac9 end
16 | 


--------------------------------------------------------------------------------
/templates/definition/meter/tibber-pulse.yaml:
--------------------------------------------------------------------------------
 1 | template: tibber-pulse
 2 | products:
 3 |   - brand: Tibber
 4 |     description:
 5 |       generic: Pulse
 6 | requirements:
 7 |   evcc: ["skiptest"]
 8 | params:
 9 |   - name: usage
10 |     choice: ["grid"]
11 |   - name: token
12 |     mask: true
13 |     required: true
14 |     example: 5K4MVS-OjfWhK_4yrjOlFe1F6kJXPVf7eQYggo8ebAE
15 |   - name: homeid
16 |     description:
17 |       generic: Home ID
18 |     example: 96a14971-525a-4420-aae9-e5aedaa129ff
19 |   - name: timeout
20 |     deprecated: true
21 | render: |
22 |   type: tibber-pulse
23 |   token: {{ .token }}
24 |   homeid: {{ .homeid }}
25 | 


--------------------------------------------------------------------------------
/templates/definition/meter/tplink.yaml:
--------------------------------------------------------------------------------
 1 | template: tplink
 2 | products:
 3 |   - brand: TP-Link
 4 |     description:
 5 |       generic: H-Series Smart Plug
 6 | group: switchsockets
 7 | params:
 8 |   - name: usage
 9 |     choice: ["pv"]
10 |   - name: host
11 | render: |
12 |   type: tplink
13 |   uri: {{ .host }}
14 | 


--------------------------------------------------------------------------------
/templates/definition/meter/tq-em.yaml:
--------------------------------------------------------------------------------
 1 | template: tq-em
 2 | products:
 3 |   - brand: TQ
 4 |     description:
 5 |       generic: Energy Manager EM2xx/EM3xx
 6 | params:
 7 |   - name: usage
 8 |     choice: ["grid"]
 9 |   - name: host
10 |   - name: port
11 |     default: 80
12 |   - name: password
13 | render: |
14 |   type: tq-em
15 |   uri: http://{{ .host }}:{{ .port }}
16 |   password: {{ .password }}
17 | 


--------------------------------------------------------------------------------
/templates/definition/meter/volkszaehler-ws.yaml:
--------------------------------------------------------------------------------
 1 | template: volkszaehler-ws
 2 | products:
 3 |   - brand: Volkszähler
 4 |     description:
 5 |       generic: WebSocket API
 6 | requirements:
 7 |   evcc: ["skiptest"]
 8 | group: generic
 9 | params:
10 |   - name: usage
11 |     choice: ["grid"]
12 |   - name: host
13 |   - name: port
14 |     default: 8082
15 |   - name: uuid
16 |     required: true
17 | render: |
18 |   type: custom
19 |   power: # power reading
20 |     source: ws # use websocket plugin
21 |     uri: ws://{{ .host }}:{{ .port }}/socket
22 |     jq: .data | select(.uuid=="{{ unquote .uuid }}") .tuples[0][1] # parse response json
23 |     timeout: 30s
24 |     scale: 1
25 | 


--------------------------------------------------------------------------------
/templates/definition/meter/wago-879-30xx.yaml:
--------------------------------------------------------------------------------
 1 | template: wago-879-30xx
 2 | products:
 3 |   - brand: Wago
 4 |     description:
 5 |       generic: 879-30xx
 6 | params:
 7 |   - name: usage
 8 |     choice: ["grid", "charge"]
 9 |   - name: modbus
10 |     choice: ["rs485"]
11 | render: |
12 |   type: mbmd
13 |   {{- include "modbus" . }}
14 |   model: wago87930
15 |   power: Power
16 |   energy: Import
17 |   currents:
18 |     - CurrentL1
19 |     - CurrentL2
20 |     - CurrentL3
21 |   powers:
22 |     - PowerL1
23 |     - PowerL2
24 |     - PowerL3
25 |   voltages:
26 |     - VoltageL1
27 |     - VoltageL2
28 |     - VoltageL3
29 | 


--------------------------------------------------------------------------------
/templates/definition/tariff/allinpower.yaml:
--------------------------------------------------------------------------------
 1 | template: allinpower
 2 | deprecated: true
 3 | products:
 4 |   - brand: All in Power
 5 | requirements:
 6 |   evcc: ["skiptest"]
 7 | group: price
 8 | countries: ["NL"]
 9 | params:
10 |   - preset: tariff-base
11 | render: |
12 |   type: custom
13 |   {{ include "tariff-base" . }}
14 |   forecast:
15 |     source: http
16 |     uri: https://api.allinpower.nl/troodon/api/p/spot_market/prices/?product_type=ELK
17 |     jq: |
18 |       [.timestamps, .prices] | transpose | map({
19 |         "start": .[0] | strptime("%FT%T.%f%z") | strftime("%FT%TZ"),
20 |         "end":   .[0] | strptime("%FT%T.%f%z") | mktime + 3600 | strftime("%FT%TZ"),
21 |         "value": .[1]
22 |       }) | tostring
23 | 


--------------------------------------------------------------------------------
/templates/definition/tariff/amber.yaml:
--------------------------------------------------------------------------------
 1 | template: amber
 2 | products:
 3 |   - brand: Amber Electric
 4 | group: price
 5 | countries: ["AU"]
 6 | params:
 7 |   - name: token
 8 |     required: true
 9 |   - name: siteid
10 |     description:
11 |       generic: Site ID
12 |     required: true
13 |   - name: channel
14 |     type: choice
15 |     choice: ["general", "feedIn", "controlledLoad"]
16 |     required: true
17 |   - preset: tariff-base
18 | render: |
19 |   type: amber
20 |   token: {{ .token }}
21 |   siteid: {{ .siteid }}
22 |   channel: {{ .channel }}
23 |   {{ include "tariff-base" . }}
24 | 


--------------------------------------------------------------------------------
/templates/definition/tariff/awattar.yaml:
--------------------------------------------------------------------------------
 1 | template: awattar
 2 | products:
 3 |   - brand: Awattar
 4 | group: price
 5 | countries: ["DE", "AT"]
 6 | params:
 7 |   - name: region
 8 |     example: AT
 9 |     type: choice
10 |     choice: ["DE", "AT"]
11 |     required: true
12 |   - preset: tariff-base
13 | render: |
14 |   type: awattar
15 |   region: {{ .region }}
16 |   {{ include "tariff-base" . }}
17 | 


--------------------------------------------------------------------------------
/templates/definition/tariff/elering.yaml:
--------------------------------------------------------------------------------
 1 | template: elering
 2 | deprecated: true
 3 | products:
 4 |   - brand: Nordpool
 5 |     description:
 6 |       generic: "Elering"
 7 | requirements:
 8 |   evcc: ["skiptest"]
 9 | group: price
10 | countries: ["EE", "LT", "LV", "FI"]
11 | params:
12 |   - name: region
13 |     example: ee
14 |     type: choice
15 |     choice: ["ee", "lt", "lv", "fi"]
16 |     required: true
17 |   - preset: tariff-base
18 | render: |
19 |   type: elering
20 |   region: {{ .region }}
21 |   {{ include "tariff-base" . }}
22 | 


--------------------------------------------------------------------------------
/templates/definition/tariff/energinet.yaml:
--------------------------------------------------------------------------------
 1 | template: energinet
 2 | deprecated: true
 3 | products:
 4 |   - brand: Energinet
 5 | requirements:
 6 |   evcc: ["skiptest"]
 7 | group: price
 8 | countries: ["DK"]
 9 | params:
10 |   - name: region
11 |     example: dk1
12 |     type: choice
13 |     choice: ["dk1", "dk2"]
14 |     required: true
15 |   - preset: tariff-base
16 | render: |
17 |   type: energinet
18 |   region: {{ .region }}
19 |   {{ include "tariff-base" . }}
20 | 


--------------------------------------------------------------------------------
/templates/definition/tariff/groupe-e.yaml:
--------------------------------------------------------------------------------
 1 | template: groupe-e
 2 | products:
 3 |   - brand: Groupe E
 4 |     description:
 5 |       generic: Vario Plus
 6 | requirements:
 7 |   evcc: ["skiptest"]
 8 | group: price
 9 | countries: ["CH"]
10 | params:
11 |   - preset: tariff-base
12 | render: |
13 |   type: groupe-e
14 |   {{ include "tariff-base" . }}
15 | 


--------------------------------------------------------------------------------
/templates/definition/tariff/gruenstromindex.yaml:
--------------------------------------------------------------------------------
 1 | template: grünstromindex
 2 | products:
 3 |   - brand: Grünstromindex
 4 | requirements:
 5 |   description:
 6 |     de: "Regionale Emissionsdaten von https://gruenstromindex.de"
 7 |     en: "Regional emission data from https://gruenstromindex.de"
 8 |   evcc: ["skiptest"]
 9 | group: co2
10 | countries: ["DE"]
11 | params:
12 |   - name: zip
13 |     required: true
14 |   - name: token
15 |     help:
16 |       de: "Token für den Zugriff auf die API von https://console.corrently.io/"
17 |       en: "Token for accessing the API from https://console.corrently.io"
18 | render: |
19 |   type: grünstromindex
20 |   features: ["cacheable"]
21 |   zip: {{ .zip }}
22 |   token: {{ .token }}
23 | 


--------------------------------------------------------------------------------
/templates/definition/tariff/pun.yaml:
--------------------------------------------------------------------------------
 1 | template: pun
 2 | products:
 3 |   - brand: PUN Orario
 4 | requirements:
 5 |   evcc: ["skiptest"]
 6 |   description:
 7 |     de: "Preisdaten von https://www.mercatoelettrico.org/it/. Wird oft zur Einspeisung ins Netz verwendet."
 8 |     en: "Price data from https://www.mercatoelettrico.org/it/. Often used for feeding into the grid."
 9 | group: price
10 | countries: ["IT"]
11 | params:
12 |   - preset: tariff-base
13 | render: |
14 |   type: pun
15 |   {{ include "tariff-base" . }}
16 | 


--------------------------------------------------------------------------------
/templates/definition/tariff/smartenergy.yaml:
--------------------------------------------------------------------------------
 1 | template: smartenergy
 2 | products:
 3 |   - brand: SmartEnergy
 4 |     description:
 5 |       generic: smartCONTROL
 6 | group: price
 7 | countries: ["AT"]
 8 | requirements:
 9 |   evcc: ["skiptest"]
10 | params:
11 |   - preset: tariff-base
12 | render: |
13 |   type: smartenergy
14 |   {{ include "tariff-base" . }}
15 | 


--------------------------------------------------------------------------------
/templates/definition/vehicle/aiways.yaml:
--------------------------------------------------------------------------------
 1 | template: aiways
 2 | products:
 3 |   - brand: Aiways
 4 | params:
 5 |   - preset: vehicle-base
 6 |   - name: vin
 7 |     required: true
 8 | render: |
 9 |   type: aiways
10 |   {{ include "vehicle-base" . }}
11 | 


--------------------------------------------------------------------------------
/templates/definition/vehicle/audi.yaml:
--------------------------------------------------------------------------------
 1 | template: audi
 2 | covers: ["etron"]
 3 | products:
 4 |   - brand: Audi
 5 | params:
 6 |   - preset: vehicle-base
 7 |   - name: vin
 8 |     example: WAUZZZ...
 9 | render: |
10 |   type: etron
11 |   {{ include "vehicle-base" . }}
12 | 


--------------------------------------------------------------------------------
/templates/definition/vehicle/carwings.yaml:
--------------------------------------------------------------------------------
 1 | template: carwings
 2 | products:
 3 |   - brand: Nissan
 4 |     description:
 5 |       generic: Leaf (pre 2019)
 6 | params:
 7 |   - preset: vehicle-base
 8 | render: |
 9 |   type: carwings
10 |   {{ include "vehicle-base" . }}
11 | 


--------------------------------------------------------------------------------
/templates/definition/vehicle/dacia.yaml:
--------------------------------------------------------------------------------
 1 | template: dacia
 2 | products:
 3 |   - brand: Dacia
 4 | params:
 5 |   - preset: vehicle-base
 6 |   - preset: vehicle-features
 7 | render: |
 8 |   type: dacia
 9 |   {{ include "vehicle-base" . }}
10 |   {{ include "vehicle-features" . }}
11 | 


--------------------------------------------------------------------------------
/templates/definition/vehicle/ford.yaml:
--------------------------------------------------------------------------------
 1 | template: ford
 2 | deprecated: true
 3 | products:
 4 |   - brand: Ford
 5 | requirements:
 6 |   description:
 7 |     de: "Hinweis: Ford hat kürzlich den API-Zugriff für seine Benutzer deaktiviert."
 8 |     en: "Note: Ford has recently disabled API-access for their users."
 9 | params:
10 |   - preset: vehicle-base
11 |   - name: vin
12 |     example: WF0FXX...
13 |   - name: domain
14 |     type: choice
15 |     choice: ["com", "de"]
16 |     default: com
17 |     required: true
18 | render: |
19 |   type: ford
20 |   {{ include "vehicle-base" . }}
21 |   domain: {{ .domain }}
22 | 


--------------------------------------------------------------------------------
/templates/definition/vehicle/jaguar-landrover.yaml:
--------------------------------------------------------------------------------
 1 | template: jaguar-landrover
 2 | deprecated: true
 3 | products:
 4 |   - brand: Jaguar
 5 |   - brand: Land Rover
 6 | params:
 7 |   - preset: vehicle-base
 8 | render: |
 9 |   type: jaguar
10 |   {{ include "vehicle-base" . }}
11 | 


--------------------------------------------------------------------------------
/templates/definition/vehicle/mg.yaml:
--------------------------------------------------------------------------------
 1 | template: mg
 2 | products:
 3 |   - brand: MG
 4 | params:
 5 |   - preset: vehicle-base
 6 |   - name: vin
 7 |     required: true
 8 |   - name: region
 9 |     description:
10 |       de: Region
11 |       en: Region
12 |     type: choice
13 |     choice: ["EU", "AU"]
14 |     default: EU
15 |     required: true
16 |     advanced: true
17 | render: |
18 |   type: mg
19 |   {{ include "vehicle-base" . }}
20 |   region: {{ .region }}
21 | 


--------------------------------------------------------------------------------
/templates/definition/vehicle/nissan-ariya.yaml:
--------------------------------------------------------------------------------
 1 | template: nissan-ariya
 2 | products:
 3 |   - brand: Nissan
 4 |     description:
 5 |       generic: Ariya
 6 | params:
 7 |   - preset: vehicle-base
 8 | render: |
 9 |   type: nissan
10 |   version: v2
11 |   {{ include "vehicle-base" . }}
12 | 


--------------------------------------------------------------------------------
/templates/definition/vehicle/nissan.yaml:
--------------------------------------------------------------------------------
 1 | template: nissan
 2 | products:
 3 |   - brand: Nissan
 4 |     description:
 5 |       generic: Leaf
 6 | params:
 7 |   - preset: vehicle-base
 8 | render: |
 9 |   type: nissan
10 |   {{ include "vehicle-base" . }}
11 | 


--------------------------------------------------------------------------------
/templates/definition/vehicle/offline.yaml:
--------------------------------------------------------------------------------
 1 | template: offline
 2 | products:
 3 |   - description:
 4 |       en: Generic vehicle (without API)
 5 |       de: Generisches Fahrzeug (ohne API)
 6 | requirements:
 7 |   description:
 8 |     de:
 9 | group: generic
10 | params:
11 |   - preset: vehicle-common
12 |   - name: coarsecurrent
13 |     advanced: true
14 |   - name: welcomecharge
15 |     advanced: true
16 | render: |
17 |   type: custom
18 |   {{- include "vehicle-common" . }}
19 |   features:
20 |   - offline
21 |   {{- if eq .coarsecurrent "true" }}
22 |   - coarsecurrent
23 |   {{- end }}
24 |   {{- if eq .welcomecharge "true" }}
25 |   - welcomecharge
26 |   {{- end }}
27 |   soc:
28 |     source: const
29 |     value: 0
30 | 


--------------------------------------------------------------------------------
/templates/definition/vehicle/polestar.yaml:
--------------------------------------------------------------------------------
 1 | template: polestar
 2 | products:
 3 |   - brand: Polestar
 4 | requirements:
 5 |   evcc: ["skiptest"]
 6 | params:
 7 |   - preset: vehicle-base
 8 |   - name: vin
 9 |     example: LPSVS...
10 | render: |
11 |   type: polestar
12 |   {{ include "vehicle-base" . }}
13 | 


--------------------------------------------------------------------------------
/templates/definition/vehicle/porsche.yaml:
--------------------------------------------------------------------------------
 1 | template: porsche
 2 | deprecated: true
 3 | products:
 4 |   - brand: Porsche
 5 | params:
 6 |   - preset: vehicle-base
 7 | render: |
 8 |   type: porsche
 9 |   {{ include "vehicle-base" . }}
10 | 


--------------------------------------------------------------------------------
/templates/definition/vehicle/seat-cupra.yaml:
--------------------------------------------------------------------------------
 1 | template: cupra
 2 | products:
 3 |   - brand: Seat
 4 |     description:
 5 |       generic: CupraConnect Gen4 (Born, Formentor, Tavascan)
 6 | params:
 7 |   - preset: vehicle-base
 8 |   - preset: vehicle-features
 9 | render: |
10 |   type: cupra
11 |   {{ include "vehicle-base" . }}
12 |   {{ include "vehicle-features" . }}
13 | 


--------------------------------------------------------------------------------
/templates/definition/vehicle/seat.yaml:
--------------------------------------------------------------------------------
 1 | template: seat
 2 | products:
 3 |   - brand: Seat
 4 |     description:
 5 |       generic: CupraConnect Gen3 (Ateca, Leon, Formentor, Tarraco)
 6 | params:
 7 |   - preset: vehicle-base
 8 | render: |
 9 |   type: seat
10 |   {{ include "vehicle-base" . }}
11 | 


--------------------------------------------------------------------------------
/templates/definition/vehicle/skoda.yaml:
--------------------------------------------------------------------------------
 1 | template: skoda
 2 | covers: ["enyaq"]
 3 | products:
 4 |   - brand: Skoda
 5 | params:
 6 |   - preset: vehicle-base
 7 |   - name: timeout
 8 | render: |
 9 |   type: skoda
10 |   {{ include "vehicle-base" . }}
11 |   timeout: {{ .timeout }}
12 | 


--------------------------------------------------------------------------------
/templates/definition/vehicle/smart-hello.yaml:
--------------------------------------------------------------------------------
 1 | template: smart-hello
 2 | products:
 3 |   - brand: Smart
 4 |     description:
 5 |       generic: "#1"
 6 | params:
 7 |   - preset: vehicle-base
 8 |   - preset: vehicle-features
 9 | render: |
10 |   type: smart-hello
11 |   {{ include "vehicle-base" . }}
12 |   {{ include "vehicle-features" . }}
13 | 


--------------------------------------------------------------------------------
/templates/definition/vehicle/toyota.yaml:
--------------------------------------------------------------------------------
 1 | template: toyota
 2 | products:
 3 |   - brand: Toyota
 4 | requirements:
 5 |   description:
 6 |     de: |
 7 |       Benötigt Toyota Connected Services Account.
 8 |     en: |
 9 |       Requires Toyota Connected Services Account.
10 | params:
11 |   - preset: vehicle-common
12 |   - name: user
13 |     required: true
14 |   - name: password
15 |     required: true
16 |   - name: vin
17 |     example: JT...
18 |   - name: cache
19 |     default: 15m
20 | render: |
21 |   type: toyota
22 |   {{ include "vehicle-common" . }}
23 |   user: {{ .user }}
24 |   password: {{ .password }}
25 |   vin: {{ .vin }}
26 |   cache: {{ .cache }}
27 | 


--------------------------------------------------------------------------------
/templates/definition/vehicle/vw.yaml:
--------------------------------------------------------------------------------
 1 | template: vw
 2 | covers: ["id"]
 3 | products:
 4 |   - brand: Volkswagen
 5 |     description:
 6 |       generic: We Connect ID
 7 | requirements:
 8 |   description:
 9 |     de: e-Golf, e-Up, ID Familie
10 |     en: e-Golf, e-Up, ID family
11 | params:
12 |   - preset: vehicle-base
13 |   - name: vin
14 |     example: WVWZZZ...
15 |   - name: timeout
16 |     default: 10s
17 |   - preset: vehicle-features
18 | render: |
19 |   type: vw
20 |   {{ include "vehicle-base" . }}
21 |   {{ include "vehicle-features" . }}
22 |   timeout: {{ .timeout }}
23 | 


--------------------------------------------------------------------------------
/templates/definition/vehicle/zero.yaml:
--------------------------------------------------------------------------------
1 | template: zero
2 | products:
3 |   - brand: Zero Motorcycles
4 | params:
5 |   - preset: vehicle-base
6 | render: |
7 |   type: zero
8 |   {{ include "vehicle-base" . }}
9 | 


--------------------------------------------------------------------------------
/templates/evcc.io/.gitignore:
--------------------------------------------------------------------------------
1 | *


--------------------------------------------------------------------------------
/tests/config-circuit.evcc.yaml:
--------------------------------------------------------------------------------
 1 | site:
 2 |   meters:
 3 |     grid: grid
 4 | 
 5 | meters:
 6 |   - name: grid
 7 |     type: template
 8 |     template: demo-meter
 9 |     power: 2070
10 |     currentL1: 3
11 |     currentL2: 3
12 |     currentL3: 3
13 | 
14 | loadpoints:
15 |   - title: Carport
16 |     charger: charger
17 |     circuit: main
18 | 
19 | circuits:
20 |   - name: main
21 |     meter: grid
22 |     maxcurrent: 16
23 | 
24 | chargers:
25 |   - name: charger
26 |     type: template
27 |     template: demo-charger
28 |     status: C
29 |     enabled: true
30 |     power: 1000
31 | 


--------------------------------------------------------------------------------
/tests/config-empty.evcc.yaml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/evcc-io/evcc/2291b371e343043037ebef13c143a8c633eeb853/tests/config-empty.evcc.yaml


--------------------------------------------------------------------------------
/tests/config-grid-only.evcc.yaml:
--------------------------------------------------------------------------------
 1 | site:
 2 |   title: Hello World
 3 |   meters:
 4 |     grid: grid
 5 | 
 6 | meters:
 7 |   - name: grid
 8 |     type: custom
 9 |     power:
10 |       source: js
11 |       script: |
12 |         1000
13 | 
14 | loadpoints:
15 |   - title: Carport
16 |     charger: charger
17 | 
18 | chargers:
19 |   - name: charger
20 |     type: custom
21 |     enable:
22 |       source: js
23 |       script:
24 |     enabled:
25 |       source: js
26 |       script: |
27 |         false
28 |     status:
29 |       source: js
30 |       script: |
31 |         "B"
32 |     maxcurrent:
33 |       source: js
34 |       script:
35 | 


--------------------------------------------------------------------------------
/tests/config-invalid-template.sql:
--------------------------------------------------------------------------------
 1 | BEGIN;
 2 | 
 3 | CREATE TABLE `configs` (
 4 |     `id` integer PRIMARY KEY AUTOINCREMENT
 5 |   , `class` integer
 6 |   , `type` text
 7 |   , `title` text
 8 |   , `icon` text
 9 |   , `product` text
10 |   , `value` text
11 | );
12 | CREATE TABLE `settings` (
13 |     `key` text
14 |   , `value` text
15 |   , PRIMARY KEY(`key`)
16 | );
17 | 
18 | INSERT INTO configs(id, class, type, title, icon, product, value) VALUES(1, 2, 'template', '', '', 'Demo meter', '{"maxacpower":"0","power_old":222,"template":"demo-meter","usage":"grid"}');
19 | INSERT INTO settings("key", value) VALUES('gridMeter', 'db:1');
20 | 
21 | COMMIT;


--------------------------------------------------------------------------------
/tests/config-one-lp.evcc.yaml:
--------------------------------------------------------------------------------
 1 | site:
 2 |   title: Hello World
 3 | 
 4 | loadpoints:
 5 |   - title: Carport
 6 |     charger: charger
 7 | 
 8 | chargers:
 9 |   - name: charger
10 |     type: custom
11 |     enable:
12 |       source: js
13 |       script:
14 |     enabled:
15 |       source: js
16 |       script: |
17 |         false
18 |     status:
19 |       source: js
20 |       script: |
21 |         "B"
22 |     maxcurrent:
23 |       source: js
24 |       script:
25 | 


--------------------------------------------------------------------------------
/tests/custom-css.css:
--------------------------------------------------------------------------------
 1 | :root {
 2 | 	--evcc-dark-green: rebeccapurple;
 3 | 	--evcc-yellow: hotpink;
 4 | }
 5 | 
 6 | [data-testid="header"],
 7 | [data-testid="footer"] {
 8 | 	display: none !important;
 9 | }
10 | 
11 | /* test against markup injection */
12 | </style><script>alert("hello");</script><style>


--------------------------------------------------------------------------------
/tests/fast.evcc.yaml:
--------------------------------------------------------------------------------
1 | interval: 0.1s
2 | 


--------------------------------------------------------------------------------
/tests/fatal-db.evcc.yaml:
--------------------------------------------------------------------------------
1 | site:
2 |   title: Hello World
3 | 
4 | database:
5 |   type: sqliteInvalid
6 |   dsn: /path/to/db
7 | 


--------------------------------------------------------------------------------
/tests/fatal-syntax.evcc.yaml:
--------------------------------------------------------------------------------
1 | s!ite:
2 |   title: Hello World
3 | 


--------------------------------------------------------------------------------
/tests/issue.evcc.yaml:
--------------------------------------------------------------------------------
 1 | interval: 10s
 2 | 
 3 | site:
 4 |   title: Hello World
 5 |   meters:
 6 |     pv: carport_pv
 7 | 
 8 | loadpoints:
 9 |   - title: Carport
10 |     charger: charger
11 | 
12 | chargers:
13 |   - name: charger
14 |     type: template
15 |     template: demo-charger
16 | 
17 | meters:
18 |   - name: carport_pv
19 |     type: template
20 |     template: demo-meter
21 |     power: 1234
22 | 


--------------------------------------------------------------------------------
/tests/loadpoint-sort.evcc.yaml:
--------------------------------------------------------------------------------
 1 | site:
 2 |   title: Loadpoint Sort Test
 3 | 
 4 | meters:
 5 |   - name: grid
 6 |     type: template
 7 |     template: demo-meter
 8 |     power: 200
 9 | 
10 | loadpoints:
11 |   - title: First Loadpoint
12 |     charger: charger_1
13 |     mode: now
14 |   - title: Second Loadpoint
15 |     charger: charger_2
16 |     mode: now
17 |   - title: Third Loadpoint
18 |     charger: charger_3
19 |     mode: now
20 | 
21 | chargers:
22 |   - name: charger_1
23 |     type: template
24 |     template: demo-charger
25 |   - name: charger_2
26 |     type: template
27 |     template: demo-charger
28 |   - name: charger_3
29 |     type: template
30 |     template: demo-charger
31 | 


--------------------------------------------------------------------------------
/tests/mqtt.ts:
--------------------------------------------------------------------------------
 1 | import mqtt from "mqtt";
 2 | 
 3 | export async function isMqttReachable(
 4 |   broker: string,
 5 |   username: string,
 6 |   password: string
 7 | ): Promise<boolean> {
 8 |   try {
 9 |     const client = mqtt.connect(`mqtt://${broker}`, {
10 |       connectTimeout: 2000,
11 |       username,
12 |       password,
13 |     });
14 | 
15 |     await new Promise<void>((resolve, reject) => {
16 |       client.once("connect", () => resolve());
17 |       client.once("error", (err) => reject(err));
18 |     });
19 | 
20 |     client.end();
21 |     return true; // connection successful
22 |   } catch {
23 |     return false; // connection failed
24 |   }
25 | }
26 | 


--------------------------------------------------------------------------------
/tests/password.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE IF NOT EXISTS `settings` (
2 |     `key` text
3 |   , `value` text
4 |   , PRIMARY KEY(`key`)
5 | );
6 | 
7 | -- password: secret
8 | INSERT INTO settings("key", value) VALUES('adminPassword', '$2a$10$HNLoqiTO5oLwopczA/wcPOebfO79S.hnAA5HOkx5p6o3g5a2E30v2');
9 | 


--------------------------------------------------------------------------------
/tests/plan-fixed-tariff.evcc.yaml:
--------------------------------------------------------------------------------
 1 | interval: 0.1s
 2 | 
 3 | loadpoints:
 4 |   - title: Loadpoint
 5 |     charger: charger
 6 | 
 7 | chargers:
 8 |   - name: charger
 9 |     type: custom
10 |     enable:
11 |       source: js
12 |       script:
13 |     enabled:
14 |       source: js
15 |       script: |
16 |         false
17 |     status:
18 |       source: js
19 |       script: |
20 |         "B"
21 |     maxcurrent:
22 |       source: js
23 |       script:
24 | 
25 | tariffs:
26 |   currency: EUR
27 |   grid:
28 |     type: fixed
29 |     price: 0.4 # EUR/kWh
30 | 


--------------------------------------------------------------------------------
/tests/sessions.evcc.yaml:
--------------------------------------------------------------------------------
 1 | interval: 0.1s
 2 | 
 3 | site:
 4 |   title: Sessions
 5 |   meters:
 6 |     grid: grid
 7 | 
 8 | meters:
 9 |   - name: grid
10 |     type: template
11 |     template: demo-meter
12 |     power: 200
13 | 
14 | loadpoints:
15 |   - title: Carport
16 |     charger: charger1
17 |     vehicle: tesla
18 |   - title: Garage
19 |     charger: charger2
20 |     vehicle: egolf
21 | 
22 | vehicles:
23 |   - name: tesla
24 |     title: weißes Model 3
25 |   - name: egolf
26 |     title: blauer e-Golf
27 | 
28 | chargers:
29 |   - name: charger1
30 |     type: template
31 |     template: demo-charger
32 |     status: B
33 |   - name: charger2
34 |     type: template
35 |     template: demo-charger
36 |     status: B
37 | 


--------------------------------------------------------------------------------
/tests/simulator/index.html:
--------------------------------------------------------------------------------
 1 | <!doctype html>
 2 | <html lang="en">
 3 |   <head>
 4 |     <meta charset="UTF-8" />
 5 |     <meta name="viewport" content="width=device-width, initial-scale=1.0" />
 6 |     <title>evcc Simulator</title>
 7 |   </head>
 8 | 
 9 |   <body>
10 |     <div id="app"></div>
11 |     <script type="module" src="./src/main.js"></script>
12 |   </body>
13 | </html>
14 | 


--------------------------------------------------------------------------------
/tests/simulator/src/main.ts:
--------------------------------------------------------------------------------
1 | import "bootstrap/dist/css/bootstrap.min.css";
2 | import "../../../assets/css/app.css";
3 | import { createApp } from "vue";
4 | import Simulator from "./Simulator.vue";
5 | 
6 | createApp(Simulator).mount("#app");
7 | 


--------------------------------------------------------------------------------
/tests/simulator/vite.config.ts:
--------------------------------------------------------------------------------
 1 | import { defineConfig } from "vite";
 2 | import vue from "@vitejs/plugin-vue";
 3 | import api from "./api";
 4 | 
 5 | export default defineConfig({
 6 |   plugins: [
 7 |     vue(),
 8 |     // @ts-expect-error the in api() declared 'enforce' property is not supported in TypeScript but in JavaScript
 9 |     api(),
10 |   ],
11 |   server: { port: 7072, host: true },
12 | });
13 | 


--------------------------------------------------------------------------------
/tests/sponsor.evcc.yaml:
--------------------------------------------------------------------------------
 1 | # expired sponsor token
 2 | sponsortoken: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJldmNjLmlvIiwic3ViIjoidHJpYWwiLCJleHAiOjE3NTQ5OTI4MDAsImlhdCI6MTc1MzY5NjgwMCwic3BlIjp0cnVlLCJzcmMiOiJtYSJ9.XKa5DHT-icCM9awcX4eS8feW0J_KIjsx2IxjcRRQOcQ
 3 | 
 4 | site:
 5 |   title: Sponsor Test
 6 | 
 7 | loadpoints:
 8 |   - title: Carport
 9 |     charger: easee_charger
10 | 
11 | chargers:
12 |   - name: easee_charger
13 |     type: template
14 |     template: easee
15 |     user: test@example.org
16 |     password: none
17 |     charger: EH123456
18 | 


--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
 1 | {
 2 |   "extends": "@vue/tsconfig/tsconfig.dom.json",
 3 |   "include": ["env.d.ts", "assets/js/**/*", "tests/**/*"],
 4 |   "compilerOptions": {
 5 |     "allowUnreachableCode": false,
 6 |     "allowUnusedLabels": false,
 7 |     "noFallthroughCasesInSwitch": true,
 8 |     "noImplicitReturns": true,
 9 |     "noPropertyAccessFromIndexSignature": true,
10 |     "noUnusedLocals": true,
11 |     "noUnusedParameters": true,
12 |     "composite": true,
13 |     "allowJs": true,
14 |     "baseUrl": ".",
15 |     "paths": {
16 |       "@/*": ["assets/js/*"]
17 |     },
18 |     "plugins": [
19 |       {
20 |         "name": "typescript-eslint-language-service"
21 |       }
22 |     ]
23 |   }
24 | }
25 | 


--------------------------------------------------------------------------------
/util/cloud/api.go:
--------------------------------------------------------------------------------
 1 | package cloud
 2 | 
 3 | import "errors"
 4 | 
 5 | var (
 6 | 	// ErrNotAuthorized indicates request token is not authorized
 7 | 	ErrNotAuthorized = errors.New("not authorized")
 8 | 
 9 | 	// ErrVehicleNotAvailable indicates vehicle not available, client should retry to prepare vehicle
10 | 	ErrVehicleNotAvailable = errors.New("vehicle not available")
11 | )
12 | 


--------------------------------------------------------------------------------
/util/config/types.go:
--------------------------------------------------------------------------------
 1 | package config
 2 | 
 3 | import (
 4 | 	"strings"
 5 | )
 6 | 
 7 | type Typed struct {
 8 | 	Type  string         `json:"type"`
 9 | 	Other map[string]any `mapstructure:",remain" yaml:",inline"` // TODO JSON serialization
10 | }
11 | 
12 | type Named struct {
13 | 	Name  string         `json:"name"`
14 | 	Type  string         `json:"type"`
15 | 	Other map[string]any `mapstructure:",remain" yaml:",inline"` // TODO JSON serialization
16 | }
17 | 
18 | // Property returns the value of the named property
19 | func (n Named) Property(key string) any {
20 | 	for k, v := range n.Other {
21 | 		if strings.EqualFold(k, key) {
22 | 			return v
23 | 		}
24 | 	}
25 | 	return nil
26 | }
27 | 


--------------------------------------------------------------------------------
/util/duration.go:
--------------------------------------------------------------------------------
 1 | package util
 2 | 
 3 | import (
 4 | 	"strconv"
 5 | 	"time"
 6 | )
 7 | 
 8 | func ParseDuration(s string) (time.Duration, error) {
 9 | 	v, err := strconv.Atoi(s)
10 | 	if err != nil {
11 | 		return 0, err
12 | 	}
13 | 
14 | 	return time.Duration(v) * time.Second, nil
15 | }
16 | 


--------------------------------------------------------------------------------
/util/encode/encode_test.go:
--------------------------------------------------------------------------------
 1 | package encode
 2 | 
 3 | import (
 4 | 	"math"
 5 | 	"testing"
 6 | 	"time"
 7 | 
 8 | 	"github.com/stretchr/testify/assert"
 9 | )
10 | 
11 | func TestEncode(t *testing.T) {
12 | 	enc := NewEncoder(WithDuration())
13 | 	assert.Equal(t, nil, enc.Encode(time.Time{}))
14 | 	assert.Equal(t, nil, enc.Encode(math.NaN()))
15 | 	assert.Equal(t, nil, enc.Encode(math.Inf(0)))
16 | 	assert.Equal(t, 30, enc.Encode(30*time.Second))
17 | 	assert.Equal(t, 3.142, enc.Encode(math.Pi))
18 | }
19 | 


--------------------------------------------------------------------------------
/util/env.go:
--------------------------------------------------------------------------------
 1 | package util
 2 | 
 3 | import (
 4 | 	"log"
 5 | 	"os"
 6 | 	"strings"
 7 | )
 8 | 
 9 | func Getenv(key string, def ...string) string {
10 | 	res := strings.TrimSpace(os.Getenv(key))
11 | 	if res == "" {
12 | 		if len(def) == 1 {
13 | 			return def[0]
14 | 		}
15 | 
16 | 		log.Fatalln("missing", key)
17 | 	}
18 | 	return res
19 | }
20 | 


--------------------------------------------------------------------------------
/util/format_functions.go:
--------------------------------------------------------------------------------
 1 | package util
 2 | 
 3 | import "time"
 4 | 
 5 | func timeRound(d time.Duration, round string) time.Duration {
 6 | 	switch round {
 7 | 	case "s", "sec":
 8 | 		return d.Round(time.Second)
 9 | 	case "m", "min":
10 | 		return d.Round(time.Minute)
11 | 	default:
12 | 		return d
13 | 	}
14 | }
15 | 
16 | func addDate(ts time.Time, y, m, d int) time.Time {
17 | 	return ts.AddDate(y, m, d)
18 | }
19 | 


--------------------------------------------------------------------------------
/util/locale/internal/types.go:
--------------------------------------------------------------------------------
1 | package internal
2 | 
3 | // ContextKey is just an empty struct. It exists so context values can be
4 | // an immutable public variable with a unique type. It's immutable
5 | // because nobody else can create a ContextKey, being unexported.
6 | type ContextKey struct{}
7 | 


--------------------------------------------------------------------------------
/util/locale/locale_test.go:
--------------------------------------------------------------------------------
 1 | package locale
 2 | 
 3 | import (
 4 | 	"os"
 5 | 	"testing"
 6 | 
 7 | 	"github.com/evcc-io/evcc/server/assets"
 8 | 	"github.com/stretchr/testify/assert"
 9 | 	"github.com/stretchr/testify/require"
10 | )
11 | 
12 | func TestLocales(t *testing.T) {
13 | 	assets.I18n = os.DirFS("../../i18n")
14 | 	require.NoError(t, Init())
15 | 	assert.Less(t, 1, len(Bundle.LanguageTags()))
16 | }
17 | 


--------------------------------------------------------------------------------
/util/log_context.go:
--------------------------------------------------------------------------------
 1 | package util
 2 | 
 3 | import (
 4 | 	"context"
 5 | )
 6 | 
 7 | var CtxLogger = struct{}{}
 8 | 
 9 | func WithLogger(ctx context.Context, log *Logger) context.Context {
10 | 	return context.WithValue(ctx, CtxLogger, log)
11 | }
12 | 


--------------------------------------------------------------------------------
/util/log_test.go:
--------------------------------------------------------------------------------
 1 | package util
 2 | 
 3 | import (
 4 | 	"testing"
 5 | 
 6 | 	"github.com/evcc-io/evcc/util/logstash"
 7 | 	jww "github.com/spf13/jwalterweatherman"
 8 | 	"github.com/stretchr/testify/require"
 9 | )
10 | 
11 | func TestLogger(t *testing.T) {
12 | 	log := NewLogger("test")
13 | 	log.TRACE.Print("foo")
14 | 
15 | 	require.Len(t, logstash.All(nil, jww.LevelTrace, 0), 1)
16 | }
17 | 


--------------------------------------------------------------------------------
/util/logstash/element.go:
--------------------------------------------------------------------------------
 1 | package logstash
 2 | 
 3 | import (
 4 | 	"regexp"
 5 | 	"slices"
 6 | 
 7 | 	jww "github.com/spf13/jwalterweatherman"
 8 | )
 9 | 
10 | type element string
11 | 
12 | var re = regexp.MustCompile(`^\[(.+?)\s*\] (\w+) `)
13 | 
14 | func (e element) areaLevel() (string, jww.Threshold) {
15 | 	m := re.FindAllStringSubmatch(string(e), 1)
16 | 	if len(m) != 1 || len(m[0]) != 3 {
17 | 		return "", jww.LevelError
18 | 	}
19 | 	return m[0][1], LogLevelToThreshold(m[0][2])
20 | }
21 | 
22 | func (e element) match(areas []string, level jww.Threshold) bool {
23 | 	a, l := e.areaLevel()
24 | 	return (len(areas) == 0 || slices.Contains(areas, a)) && l >= level
25 | }
26 | 


--------------------------------------------------------------------------------
/util/logstash/levels.go:
--------------------------------------------------------------------------------
 1 | package logstash
 2 | 
 3 | import (
 4 | 	"strings"
 5 | 
 6 | 	jww "github.com/spf13/jwalterweatherman"
 7 | )
 8 | 
 9 | // LogLevelToThreshold converts log level string to a jww Threshold
10 | func LogLevelToThreshold(level string) jww.Threshold {
11 | 	switch strings.ToUpper(level) {
12 | 	case "FATAL":
13 | 		return jww.LevelFatal
14 | 	case "ERROR":
15 | 		return jww.LevelError
16 | 	case "WARN":
17 | 		return jww.LevelWarn
18 | 	case "INFO":
19 | 		return jww.LevelInfo
20 | 	case "DEBUG":
21 | 		return jww.LevelDebug
22 | 	case "TRACE":
23 | 		return jww.LevelTrace
24 | 	default:
25 | 		return jww.LevelError
26 | 	}
27 | }
28 | 


--------------------------------------------------------------------------------
/util/metering.go:
--------------------------------------------------------------------------------
 1 | package util
 2 | 
 3 | // SignFromPower is a helper function to create signed current from signed power bypassing already signed current
 4 | func SignFromPower(current, power float64) float64 {
 5 | 	if current > 0 && power < 0 {
 6 | 		return -current
 7 | 	}
 8 | 	return current
 9 | }
10 | 


--------------------------------------------------------------------------------
/util/modbus/mutex.go:
--------------------------------------------------------------------------------
 1 | package modbus
 2 | 
 3 | import "sync"
 4 | 
 5 | var mu2 sync.Mutex
 6 | 
 7 | func Lock() {
 8 | 	mu2.Lock()
 9 | }
10 | 
11 | func Unlock() {
12 | 	mu2.Unlock()
13 | }
14 | 


--------------------------------------------------------------------------------
/util/param_test.go:
--------------------------------------------------------------------------------
 1 | package util
 2 | 
 3 | import (
 4 | 	"testing"
 5 | 
 6 | 	"github.com/stretchr/testify/assert"
 7 | )
 8 | 
 9 | func TestParam(t *testing.T) {
10 | 	lp := 2
11 | 	p := Param{
12 | 		Key: "power",
13 | 		Val: 4711,
14 | 	}
15 | 	assert.Equal(t, "power", p.UniqueID())
16 | 
17 | 	p.Loadpoint = &lp
18 | 	assert.Equal(t, "2.power", p.UniqueID())
19 | }
20 | 
21 | func TestParamCache(t *testing.T) {
22 | 	NewParamCache().Add("foo", Param{})
23 | }
24 | 


--------------------------------------------------------------------------------
/util/request/json.go:
--------------------------------------------------------------------------------
 1 | package request
 2 | 
 3 | import (
 4 | 	"bytes"
 5 | 	"encoding/json"
 6 | 	"io"
 7 | )
 8 | 
 9 | // errorReader wraps an error with an io.Reader
10 | type errorReader struct {
11 | 	err error
12 | }
13 | 
14 | func (r *errorReader) Read(p []byte) (int, error) {
15 | 	return 0, r.err
16 | }
17 | 
18 | func (r *errorReader) Seek(offset int64, whence int) (int64, error) {
19 | 	return 0, r.err
20 | }
21 | 
22 | // MarshalJSON marshals JSON into an io.ReadSeeker
23 | func MarshalJSON(data any) io.ReadSeeker {
24 | 	if data == nil {
25 | 		return nil
26 | 	}
27 | 
28 | 	body, err := json.Marshal(data)
29 | 	if err != nil {
30 | 		return &errorReader{err: err}
31 | 	}
32 | 
33 | 	return bytes.NewReader(body)
34 | }
35 | 


--------------------------------------------------------------------------------
/util/request/xml.go:
--------------------------------------------------------------------------------
 1 | package request
 2 | 
 3 | import (
 4 | 	"bytes"
 5 | 	"encoding/xml"
 6 | 	"io"
 7 | )
 8 | 
 9 | // MarshalXML marshals XML into an io.ReadSeeker
10 | func MarshalXML(data any) io.ReadSeeker {
11 | 	if data == nil {
12 | 		return nil
13 | 	}
14 | 
15 | 	body, err := xml.Marshal(data)
16 | 	if err != nil {
17 | 		return &errorReader{err: err}
18 | 	}
19 | 
20 | 	return bytes.NewReader(body)
21 | }
22 | 


--------------------------------------------------------------------------------
/util/telemetry/types.go:
--------------------------------------------------------------------------------
 1 | package telemetry
 2 | 
 3 | type InstanceChargeProgress struct {
 4 | 	InstanceID string `json:"instanceId"`
 5 | 	ChargeProgress
 6 | }
 7 | 
 8 | type ChargeProgress struct {
 9 | 	ChargePower  float64 `json:"chargePower"`
10 | 	GreenPower   float64 `json:"greenPower"`
11 | 	ChargeEnergy float64 `json:"chargeEnergy"`
12 | 	GreenEnergy  float64 `json:"greenEnergy"`
13 | }
14 | 


--------------------------------------------------------------------------------
/util/templates/class.go:
--------------------------------------------------------------------------------
 1 | package templates
 2 | 
 3 | type Class int
 4 | 
 5 | //go:generate go tool enumer -type Class -transform=lower
 6 | const (
 7 | 	_ Class = iota
 8 | 	Charger
 9 | 	Meter
10 | 	Vehicle
11 | 	Tariff
12 | 	Loadpoint
13 | 	Circuit
14 | )
15 | 


--------------------------------------------------------------------------------
/util/templates/includes/eebus.tpl:
--------------------------------------------------------------------------------
1 | {{ define "eebus" }}
2 | type: eebus
3 | ski: {{ .ski }}
4 | {{ if .ip }}ip: {{ .ip }}{{ end }}
5 | {{- end}}
6 | 


--------------------------------------------------------------------------------
/util/templates/includes/mqtt.tpl:
--------------------------------------------------------------------------------
 1 | {{ define "mqtt" }}
 2 | broker: {{ .host }}:{{ .port }}
 3 | {{- if .user }}
 4 | user: {{ .user }}
 5 | {{- end }}
 6 | {{- if .password }}
 7 | password: {{ .password }}
 8 | {{- end }}
 9 | {{- if ne .timeout "30s" }}
10 | timeout: {{ .timeout }}
11 | {{- end }}
12 | {{- if .caCert }}
13 | caCert: {{ .caCert }}
14 | {{- end }}
15 | {{- if .clientCert }}
16 | clientCert: {{ .clientCert }}
17 | {{- end }}
18 | {{- if .clientKey }}
19 | clientKey: {{ .clientKey }}
20 | {{- end }}
21 | {{- end }}
22 | 


--------------------------------------------------------------------------------
/util/templates/includes/switchsocket.tpl:
--------------------------------------------------------------------------------
 1 | {{ define "switchsocket" }}
 2 | standbypower: {{ .standbypower }}
 3 | features:
 4 | {{- if and .integrateddevice (ne .integrateddevice "false") }}
 5 | - integrateddevice
 6 | {{- end }}
 7 | {{- if and .heating (ne .heating "false") }}
 8 | - heating
 9 | {{- end }}
10 | {{- if .icon }}
11 | icon: {{ .icon }}
12 | {{- end }}
13 | {{- end }}
14 | 


--------------------------------------------------------------------------------
/util/templates/includes/tariff-base.tpl:
--------------------------------------------------------------------------------
 1 | {{ define "tariff-base" }}
 2 | {{- if .charges }}
 3 | charges: {{ .charges }}
 4 | {{- end }}
 5 | {{- if .tax }}
 6 | tax: {{ .tax }}
 7 | {{- end }}
 8 | {{- if .formula }}
 9 | formula: {{ .formula }}
10 | {{- end }}
11 | {{- end }}
12 | 


--------------------------------------------------------------------------------
/util/templates/includes/tariff-features.tpl:
--------------------------------------------------------------------------------
1 | {{ define "tariff-features" }}
2 | {{- if eq .average "true" }}
3 | features: ["average"]
4 | {{- end }}
5 | {{- end }}
6 | 


--------------------------------------------------------------------------------
/util/templates/includes/vehicle-base.tpl:
--------------------------------------------------------------------------------
 1 | {{ define "vehicle-base" }}
 2 | user: {{ .user }}
 3 | password: {{ .password }}
 4 | vin: {{ .vin }}
 5 | {{ template "vehicle-common" . }}
 6 | {{- if .cache }}
 7 | cache: {{ .cache }}
 8 | {{- end }}
 9 | {{- end }}
10 | 


--------------------------------------------------------------------------------
/util/templates/includes/vehicle-features.tpl:
--------------------------------------------------------------------------------
 1 | {{ define "vehicle-features" }}
 2 | {{- if or (eq .coarsecurrent "true") (eq .welcomecharge "true") (eq .streaming "true") }}
 3 | features:
 4 | {{- if eq .coarsecurrent "true" }}
 5 | - coarsecurrent
 6 | {{- end }}
 7 | {{- if eq .welcomecharge "true" }}
 8 | - welcomecharge
 9 | {{- end }}
10 | {{- if eq .streaming "true" }}
11 | - streaming
12 | {{- end }}
13 | {{- end }}
14 | {{- end }}
15 | 


--------------------------------------------------------------------------------
/util/templates/includes/vehicle-language.tpl:
--------------------------------------------------------------------------------
1 | {{ define "vehicle-language" }}
2 | language: {{ .language }}
3 | {{- end }}
4 | 


--------------------------------------------------------------------------------
/util/templates/merge_test.go:
--------------------------------------------------------------------------------
 1 | package templates
 2 | 
 3 | import (
 4 | 	"testing"
 5 | 
 6 | 	"github.com/stretchr/testify/require"
 7 | )
 8 | 
 9 | func TestMergeMaps(t *testing.T) {
10 | 	target := map[string]any{
11 | 		"foo": "bar",
12 | 		"nested": map[string]any{
13 | 			"bar": "baz",
14 | 		},
15 | 	}
16 | 	other := map[string]any{
17 | 		"Foo": 1,
18 | 		"Nested": map[string]any{
19 | 			"Bar": 2,
20 | 		},
21 | 		"baz": 3,
22 | 	}
23 | 
24 | 	require.NoError(t, mergeMaps(other, target))
25 | 	require.Equal(t, map[string]any{
26 | 		"foo": 1,
27 | 		"nested": map[string]any{
28 | 			"bar": 2,
29 | 		},
30 | 		"baz": 3,
31 | 	}, target)
32 | }
33 | 


--------------------------------------------------------------------------------
/util/templates/paramtype.go:
--------------------------------------------------------------------------------
 1 | package templates
 2 | 
 3 | type ParamType int
 4 | 
 5 | //go:generate go tool enumer -type ParamType -trimprefix Type -text
 6 | const (
 7 | 	TypeString ParamType = iota // default type string
 8 | 	TypeBool
 9 | 	TypeChoice
10 | 	TypeChargeModes
11 | 	TypeDuration
12 | 	TypeFloat
13 | 	TypeInt
14 | 	TypeList
15 | )
16 | 


--------------------------------------------------------------------------------
/util/templates/proxy.tpl:
--------------------------------------------------------------------------------
 1 | type: template
 2 | template: {{ .Template }}
 3 | {{- range .Params }}
 4 | {{- if or (ne (len .Value) 0) (ne (len .Values) 0) }} 
 5 | {{ .Name }}:
 6 | 	{{- if len .Value }} {{ .Value }} {{ end }}
 7 | {{- if ne (len .Values) 0 }} 
 8 | {{- range .Values }}
 9 | - {{ . }}
10 | {{- end }}
11 | {{- end }}
12 | {{- end -}}
13 | {{ end -}}
14 | 


--------------------------------------------------------------------------------
/util/templates/usage.go:
--------------------------------------------------------------------------------
 1 | package templates
 2 | 
 3 | type Usage int
 4 | 
 5 | //go:generate go tool enumer -type Usage -trimprefix Usage -transform=lower -text
 6 | const (
 7 | 	UsageGrid Usage = iota
 8 | 	UsagePV
 9 | 	UsageBattery
10 | 	UsageCharge
11 | 	UsageAux
12 | )
13 | 


--------------------------------------------------------------------------------
/util/test/ci.go:
--------------------------------------------------------------------------------
 1 | package test
 2 | 
 3 | import (
 4 | 	"os"
 5 | 	"testing"
 6 | )
 7 | 
 8 | func SkipCI(t *testing.T) {
 9 | 	t.Helper()
10 | 
11 | 	if os.Getenv("CI") != "" {
12 | 		t.Skip("Skipping testing in CI environment")
13 | 	}
14 | }
15 | 


--------------------------------------------------------------------------------
/util/test/errors.go:
--------------------------------------------------------------------------------
 1 | package test
 2 | 
 3 | import (
 4 | 	"strings"
 5 | )
 6 | 
 7 | // Acceptable checks if a test error is in the list of acceptable errors
 8 | func Acceptable(err error, acceptable []string) bool {
 9 | 	for _, msg := range acceptable {
10 | 		err := strings.TrimSpace(err.Error())
11 | 		if strings.HasPrefix(err, msg) || strings.HasSuffix(err, msg) {
12 | 			return true
13 | 		}
14 | 	}
15 | 
16 | 	return false
17 | }
18 | 


--------------------------------------------------------------------------------
/util/token.go:
--------------------------------------------------------------------------------
 1 | package util
 2 | 
 3 | import (
 4 | 	"time"
 5 | 
 6 | 	"golang.org/x/oauth2"
 7 | )
 8 | 
 9 | func TokenWithExpiry(token *oauth2.Token) *oauth2.Token {
10 | 	if token != nil && token.Expiry.IsZero() && token.ExpiresIn != 0 {
11 | 		token.Expiry = time.Now().Add(time.Second * time.Duration(token.ExpiresIn))
12 | 	}
13 | 	return token
14 | }
15 | 


--------------------------------------------------------------------------------
/util/transport/basicauth.go:
--------------------------------------------------------------------------------
 1 | package transport
 2 | 
 3 | import (
 4 | 	"encoding/base64"
 5 | 	"net/http"
 6 | )
 7 | 
 8 | // BasicAuthHeader returns the basic auth header
 9 | func BasicAuthHeader(user, password string) string {
10 | 	return "Basic " + base64.StdEncoding.EncodeToString([]byte(user+":"+password))
11 | }
12 | 
13 | // BasicAuth creates an http transport performing basic auth
14 | func BasicAuth(user, password string, base http.RoundTripper) http.RoundTripper {
15 | 	return &Decorator{
16 | 		Decorator: DecorateHeaders(map[string]string{
17 | 			"Authorization": BasicAuthHeader(user, password),
18 | 		}),
19 | 		Base: base,
20 | 	}
21 | }
22 | 


--------------------------------------------------------------------------------
/util/transport/bearer.go:
--------------------------------------------------------------------------------
 1 | package transport
 2 | 
 3 | import (
 4 | 	"net/http"
 5 | )
 6 | 
 7 | // BearerAuth creates an HTTP transport performing HTTP authorization using an OAuth 2.0 Bearer Token
 8 | func BearerAuth(token string, base http.RoundTripper) http.RoundTripper {
 9 | 	return &Decorator{
10 | 		Decorator: DecorateHeaders(map[string]string{
11 | 			"Authorization": "Bearer " + token,
12 | 		}),
13 | 		Base: base,
14 | 	}
15 | }
16 | 


--------------------------------------------------------------------------------
/util/version.go:
--------------------------------------------------------------------------------
 1 | package util
 2 | 
 3 | import "fmt"
 4 | 
 5 | const DevVersion = "0.0.0"
 6 | 
 7 | var (
 8 | 	// Version of executable
 9 | 	Version = DevVersion
10 | 
11 | 	// Commit of executable
12 | 	Commit = ""
13 | )
14 | 
15 | func FormattedVersion() string {
16 | 	if Commit != "" {
17 | 		return fmt.Sprintf("%s (%s)", Version, Commit)
18 | 	}
19 | 	return Version
20 | }
21 | 


--------------------------------------------------------------------------------
/vehicle/audi/etron/params.go:
--------------------------------------------------------------------------------
 1 | package etron
 2 | 
 3 | import "net/url"
 4 | 
 5 | // Authorization parameters
 6 | var AuthParams = url.Values{
 7 | 	"response_type": {"code id_token token"},
 8 | 	"client_id":     {"f4d0934f-32bf-4ce4-b3c4-699a7049ad26@apps_vw-dilab_com"},
 9 | 	"redirect_uri":  {"myaudi:///"},
10 | 	"scope":         {"openid profile mbb"}, // vin badge birthdate nickname email address phone name picture
11 | 	"prompt":        {"login"},
12 | 	"ui_locales":    {"de-DE"},
13 | }
14 | 
15 | var IDKParams = url.Values{
16 | 	"client_id":    {"f4d0934f-32bf-4ce4-b3c4-699a7049ad26@apps_vw-dilab_com"},
17 | 	"redirect_uri": {"myaudi:///"},
18 | }
19 | 
20 | const AZSConfig = "myaudi"
21 | 


--------------------------------------------------------------------------------
/vehicle/audi/etron/types.go:
--------------------------------------------------------------------------------
1 | package etron
2 | 
3 | type Vehicle struct {
4 | 	VIN, Type, Nickname string
5 | }
6 | 


--------------------------------------------------------------------------------
/vehicle/bmw/connected/types.go:
--------------------------------------------------------------------------------
 1 | package bmw
 2 | 
 3 | type Vehicle struct {
 4 | 	VIN            string
 5 | 	Model          string
 6 | 	AppVehicleType string
 7 | }
 8 | 
 9 | type VehicleStatus struct {
10 | 	StatusCode int
11 | 	Message    string
12 | 	State      struct {
13 | 		CurrentMileage        int64
14 | 		Range                 int64
15 | 		ElectricChargingState struct {
16 | 			ChargingLevelPercent int64
17 | 			Range                int64
18 | 			IsChargerConnected   bool
19 | 			ChargingStatus       string
20 | 			ChargingTarget       int64
21 | 		}
22 | 		ClimateControlState struct {
23 | 			Activity string
24 | 		}
25 | 	}
26 | }
27 | 


--------------------------------------------------------------------------------
/vehicle/ford/autonomic/types.go:
--------------------------------------------------------------------------------
 1 | package autonomic
 2 | 
 3 | import "time"
 4 | 
 5 | type IntValue struct {
 6 | 	UpdateTime time.Time
 7 | 	Value      int
 8 | }
 9 | type FloatValue struct {
10 | 	UpdateTime time.Time
11 | 	Value      float64
12 | }
13 | type StringValue struct {
14 | 	UpdateTime time.Time
15 | 	Value      string
16 | }
17 | 
18 | type MetricsResponse struct {
19 | 	Metrics struct {
20 | 		Position struct {
21 | 			Value struct {
22 | 				Location struct {
23 | 					Lat, Lon float64
24 | 				}
25 | 			}
26 | 		}
27 | 		Odometer                FloatValue
28 | 		XevPlugChargerStatus    StringValue
29 | 		XevBatteryRange         FloatValue
30 | 		XevBatteryStateOfCharge FloatValue
31 | 	}
32 | }
33 | 


--------------------------------------------------------------------------------
/vehicle/ford/types.go:
--------------------------------------------------------------------------------
 1 | package ford
 2 | 
 3 | type VehiclesResponse struct {
 4 | 	UserVehicles struct {
 5 | 		VehicleDetails []struct {
 6 | 			VIN string
 7 | 		}
 8 | 	}
 9 | }
10 | 


--------------------------------------------------------------------------------
/vehicle/psa/helper.go:
--------------------------------------------------------------------------------
 1 | package psa
 2 | 
 3 | import (
 4 | 	"sync"
 5 | 
 6 | 	"golang.org/x/oauth2"
 7 | )
 8 | 
 9 | var (
10 | 	mu         sync.Mutex
11 | 	identities = make(map[string]oauth2.TokenSource)
12 | )
13 | 
14 | func getInstance(subject string) oauth2.TokenSource {
15 | 	return identities[subject]
16 | }
17 | 
18 | func addInstance(subject string, identity oauth2.TokenSource) {
19 | 	identities[subject] = identity
20 | }
21 | 


--------------------------------------------------------------------------------
/vehicle/saic/requests/api_config.go:
--------------------------------------------------------------------------------
1 | package requests
2 | 
3 | const (
4 | 	CONTENT_ENCRYPTED    = "1"
5 | 	PARAM_AUTHENTICATION = "Basic c3dvcmQ6c3dvcmRfc2VjcmV0"
6 | 	TENANT_ID            = "459771"
7 | 	USER_TYPE            = "app"
8 | )
9 | 


--------------------------------------------------------------------------------
/vehicle/saic/requests/hashUtils.go:
--------------------------------------------------------------------------------
 1 | package requests
 2 | 
 3 | import (
 4 | 	"crypto/md5"
 5 | 	"crypto/sha1"
 6 | 	"crypto/sha256"
 7 | 	"encoding/hex"
 8 | )
 9 | 
10 | func Md5(value string) string {
11 | 	if len(value) == 0 {
12 | 		return ""
13 | 	}
14 | 	result := md5.Sum([]byte(value))
15 | 	return hex.EncodeToString(result[:])
16 | }
17 | 
18 | func Sha1(value string) string {
19 | 	if len(value) == 0 {
20 | 		return ""
21 | 	}
22 | 	result := sha1.Sum([]byte(value))
23 | 	return hex.EncodeToString(result[:])
24 | }
25 | 
26 | func Sha256(value string) string {
27 | 	if len(value) == 0 {
28 | 		return ""
29 | 	}
30 | 	result := sha256.Sum256([]byte(value))
31 | 	return hex.EncodeToString(result[:])
32 | }
33 | 


--------------------------------------------------------------------------------
/vehicle/saic/requests/macUtils.go:
--------------------------------------------------------------------------------
 1 | package requests
 2 | 
 3 | import (
 4 | 	"crypto/hmac"
 5 | 	"crypto/sha256"
 6 | 	"encoding/hex"
 7 | )
 8 | 
 9 | func HmacSha256(secret string, message string) string {
10 | 	if len(secret) == 0 || len(message) == 0 {
11 | 		return ""
12 | 	}
13 | 
14 | 	key := []byte(secret)
15 | 	h := hmac.New(sha256.New, key)
16 | 	h.Write([]byte(message))
17 | 	return hex.EncodeToString(h.Sum(nil))
18 | }
19 | 


--------------------------------------------------------------------------------
/vehicle/seat/cupra/params.go:
--------------------------------------------------------------------------------
 1 | package cupra
 2 | 
 3 | import (
 4 | 	"golang.org/x/oauth2"
 5 | )
 6 | 
 7 | var OAuth2Config = &oauth2.Config{
 8 | 	ClientID:     "3c756d46-f1ba-4d78-9f9a-cff0d5292d51@apps_vw-dilab_com",
 9 | 	ClientSecret: "eb8814e641c81a2640ad62eeccec11c98effc9bccd4269ab7af338b50a94b3a2",
10 | 	RedirectURL:  "cupra://oauth-callback",
11 | 	Scopes:       []string{"openid", "profile", "mbb"},
12 | }
13 | 


--------------------------------------------------------------------------------
/vehicle/seat/params.go:
--------------------------------------------------------------------------------
 1 | package seat
 2 | 
 3 | import "net/url"
 4 | 
 5 | const (
 6 | 	Brand   = "VW"
 7 | 	Country = "ES"
 8 | 
 9 | 	// Authorization ClientID
10 | 	AuthClientID = "9dcc70f0-8e79-423a-a3fa-4065d99088b4"
11 | )
12 | 
13 | // Authorization parameters
14 | var AuthParams = url.Values{
15 | 	"response_type": {"code id_token"}, // token
16 | 	"client_id":     {"3c8e98bc-3ae9-4277-a563-d5ee65ddebba@apps_vw-dilab_com"},
17 | 	"redirect_uri":  {"seatconnect://identity-kit/login"},
18 | 	"scope":         {"openid profile"}, // address phone email birthdate nationalIdentifier cars mbb dealers badge nationality
19 | }
20 | 


--------------------------------------------------------------------------------
/vehicle/skoda/params.go:
--------------------------------------------------------------------------------
 1 | package skoda
 2 | 
 3 | import "net/url"
 4 | 
 5 | const (
 6 | 	Brand   = "VW"
 7 | 	Country = "CZ"
 8 | 
 9 | 	// Authorization ClientID
10 | 	AuthClientID = "afb0473b-6d82-42b8-bfea-cead338c46ef"
11 | )
12 | 
13 | // Skoda native api
14 | var AuthParams = url.Values{
15 | 	"response_type": {"code id_token"},
16 | 	"client_id":     {"7f045eee-7003-4379-9968-9355ed2adb06@apps_vw-dilab_com"},
17 | 	"redirect_uri":  {"myskoda://redirect/login/"},
18 | 	"scope":         {"address badge birthdate cars driversLicense dealers email mileage mbb nationalIdentifier openid phone profession profile vin"},
19 | }
20 | 
21 | // TokenRefreshService parameters
22 | var TRSParams = url.Values{
23 | 	"brand": {"skoda"},
24 | }
25 | 


--------------------------------------------------------------------------------
/vehicle/smart/hello/const.go:
--------------------------------------------------------------------------------
 1 | package hello
 2 | 
 3 | const (
 4 | 	ApiURI = "https://api.ecloudeu.com"
 5 | 	ApiKey = "3_L94eyQ-wvJhWm7Afp1oBhfTGXZArUfSHHW9p9Pncg513hZELXsxCfMWHrF8f5P5a"
 6 | 
 7 | 	appID        = "SmartAPPEU"
 8 | 	operatorCode = "SMART"
 9 | 	userAgent    = "Mozilla/5.0 (Linux; Android 9; ANE-LX1 Build/HUAWEIANE-L21; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/118.0.0.0 Mobile Safari/537.36"
10 | )
11 | 


--------------------------------------------------------------------------------
/vehicle/template.go:
--------------------------------------------------------------------------------
 1 | package vehicle
 2 | 
 3 | import (
 4 | 	"context"
 5 | 
 6 | 	"github.com/evcc-io/evcc/api"
 7 | 	"github.com/evcc-io/evcc/util/templates"
 8 | )
 9 | 
10 | func init() {
11 | 	registry.AddCtx("template", NewVehicleFromTemplateConfig)
12 | }
13 | 
14 | func NewVehicleFromTemplateConfig(ctx context.Context, other map[string]any) (api.Vehicle, error) {
15 | 	instance, err := templates.RenderInstance(templates.Vehicle, other)
16 | 	if err != nil {
17 | 		return nil, err
18 | 	}
19 | 
20 | 	return NewFromConfig(ctx, instance.Type, instance.Other)
21 | }
22 | 


--------------------------------------------------------------------------------
/vehicle/tesla/helper_test.go:
--------------------------------------------------------------------------------
 1 | package tesla
 2 | 
 3 | import (
 4 | 	"testing"
 5 | 
 6 | 	"github.com/stretchr/testify/assert"
 7 | )
 8 | 
 9 | func TestApiError(t *testing.T) {
10 | 	assert.Nil(t, apiError(nil))
11 | }
12 | 


--------------------------------------------------------------------------------
/vehicle/tesla/types.go:
--------------------------------------------------------------------------------
 1 | package tesla
 2 | 
 3 | import (
 4 | 	tesla "github.com/evcc-io/tesla-proxy-client"
 5 | )
 6 | 
 7 | type (
 8 | 	Vehicle         = tesla.Vehicle
 9 | 	VehicleData     = tesla.VehicleData
10 | 	CommandResponse = tesla.CommandResponse
11 | )
12 | 
13 | type RegionResponse struct {
14 | 	Response Region
15 | }
16 | 
17 | type Region struct {
18 | 	Region          string
19 | 	FleetApiBaseUrl string `json:"fleet_api_base_url"`
20 | }
21 | 


--------------------------------------------------------------------------------
/vehicle/toyota/provider.go:
--------------------------------------------------------------------------------
 1 | package toyota
 2 | 
 3 | import (
 4 | 	"time"
 5 | 
 6 | 	"github.com/evcc-io/evcc/util"
 7 | )
 8 | 
 9 | type Provider struct {
10 | 	status func() (Status, error)
11 | }
12 | 
13 | func NewProvider(api *API, vin string, cache time.Duration) *Provider {
14 | 	impl := &Provider{
15 | 		status: util.Cached(func() (Status, error) {
16 | 			return api.Status(vin)
17 | 		}, cache),
18 | 	}
19 | 	return impl
20 | }
21 | 
22 | func (v *Provider) Soc() (float64, error) {
23 | 	res, err := v.status()
24 | 	return float64(res.Payload.BatteryLevel), err
25 | }
26 | 


--------------------------------------------------------------------------------
/vehicle/tronity/auth.go:
--------------------------------------------------------------------------------
 1 | package tronity
 2 | 
 3 | import (
 4 | 	"golang.org/x/oauth2"
 5 | )
 6 | 
 7 | const URI = "https://api.tronity.tech"
 8 | 
 9 | func OAuth2Config(id, secret string) (*oauth2.Config, error) {
10 | 	return &oauth2.Config{
11 | 		ClientID:     id,
12 | 		ClientSecret: secret,
13 | 		Endpoint: oauth2.Endpoint{
14 | 			AuthURL:  "https://auth.tronity.io/oauth/v2/authorize",
15 | 			TokenURL: "https://api.tronity.tech/authentication",
16 | 		},
17 | 		Scopes: []string{"read_vin", "read_vehicle_info", "read_odometer", "read_charge", "read_charge", "read_battery", "read_location", "write_charge_start_stop", "write_wake_up"},
18 | 	}, nil
19 | }
20 | 


--------------------------------------------------------------------------------
/vehicle/vag/cariad/const.go:
--------------------------------------------------------------------------------
1 | package cariad
2 | 
3 | const BaseURL = "https://emea.bff.cariad.digital"
4 | 


--------------------------------------------------------------------------------
/vehicle/vag/challenge.go:
--------------------------------------------------------------------------------
 1 | package vag
 2 | 
 3 | import (
 4 | 	"net/url"
 5 | 
 6 | 	"golang.org/x/oauth2"
 7 | )
 8 | 
 9 | func ChallengeAndVerifier(q url.Values) func(url.Values) {
10 | 	cv := oauth2.GenerateVerifier()
11 | 
12 | 	q.Set("code_challenge_method", "S256")
13 | 	q.Set("code_challenge", oauth2.S256ChallengeFromVerifier(cv))
14 | 
15 | 	return func(q url.Values) {
16 | 		q.Set("code_verifier", cv)
17 | 	}
18 | }
19 | 


--------------------------------------------------------------------------------
/vehicle/vag/loginapps/token.go:
--------------------------------------------------------------------------------
 1 | package loginapps
 2 | 
 3 | import (
 4 | 	"encoding/json"
 5 | 	"time"
 6 | 
 7 | 	"golang.org/x/oauth2"
 8 | )
 9 | 
10 | // Token is the loginapps token
11 | type Token oauth2.Token
12 | 
13 | func (t *Token) UnmarshalJSON(data []byte) error {
14 | 	var s struct {
15 | 		AccessToken  string
16 | 		RefreshToken string
17 | 	}
18 | 
19 | 	err := json.Unmarshal(data, &s)
20 | 	if err == nil {
21 | 		t.TokenType = "bearer"
22 | 		t.AccessToken = s.AccessToken
23 | 		t.RefreshToken = s.RefreshToken
24 | 		t.Expiry = time.Now().Add(time.Hour)
25 | 	}
26 | 
27 | 	return err
28 | }
29 | 


--------------------------------------------------------------------------------
/vehicle/vag/loginapps/token_test.go:
--------------------------------------------------------------------------------
 1 | package loginapps
 2 | 
 3 | import (
 4 | 	"encoding/json"
 5 | 	"testing"
 6 | )
 7 | 
 8 | func TestUnmarshalJSON(t *testing.T) {
 9 | 	var tok Token
10 | 	str := `{"accesstoken":"access","refreshtoken":"refresh"}`
11 | 
12 | 	if err := json.Unmarshal([]byte(str), &tok); err != nil {
13 | 		t.Error(err)
14 | 	}
15 | 
16 | 	if tok.AccessToken != "access" {
17 | 		t.Error("AccessToken")
18 | 	}
19 | 
20 | 	if tok.RefreshToken != "refresh" {
21 | 		t.Error("RefreshToken")
22 | 	}
23 | 
24 | 	if tok.TokenType != "bearer" {
25 | 		t.Error("TokenType")
26 | 	}
27 | 
28 | 	if tok.Expiry.IsZero() {
29 | 		t.Error("Expiry")
30 | 	}
31 | }
32 | 


--------------------------------------------------------------------------------
/vehicle/vw/id/params.go:
--------------------------------------------------------------------------------
 1 | package id
 2 | 
 3 | import (
 4 | 	"net/url"
 5 | 
 6 | 	"github.com/evcc-io/evcc/vehicle/vag/cariad"
 7 | )
 8 | 
 9 | const LoginURL = cariad.BaseURL + "/user-login/v1/authorize"
10 | 
11 | var AuthParams = url.Values{
12 | 	"response_type": {"code id_token token"},
13 | 	"client_id":     {"a24fba63-34b3-4d43-b181-942111e6bda8@apps_vw-dilab_com"},
14 | 	"redirect_uri":  {"weconnect://authenticated"},
15 | 	"scope":         {"openid profile badge cars vin"}, // dealers
16 | }
17 | 


--------------------------------------------------------------------------------
/vehicle/vw/params.go:
--------------------------------------------------------------------------------
 1 | package vw
 2 | 
 3 | import "net/url"
 4 | 
 5 | const (
 6 | 	Brand   = "VW"
 7 | 	Country = "DE"
 8 | 
 9 | 	// Authorization ClientID
10 | 	AuthClientID = "38761134-34d0-41f3-9a73-c4be88d7d337"
11 | )
12 | 
13 | // Authorization parameters
14 | var AuthParams = url.Values{
15 | 	"response_type": {"code id_token token"},
16 | 	"client_id":     {"9496332b-ea03-4091-a224-8c746b885068@apps_vw-dilab_com"},
17 | 	"redirect_uri":  {"carnet://identity-kit/login"},
18 | 	"scope":         {"openid profile mbb"}, // cars birthdate nickname address phone
19 | }
20 | 
21 | // TokenRefreshService parameters
22 | var TRSParams = url.Values{
23 | 	"brand": {"vw"},
24 | }
25 | 


--------------------------------------------------------------------------------
/vitest.config.ts:
--------------------------------------------------------------------------------
 1 | import { mergeConfig } from "vite";
 2 | import { defineConfig } from "vitest/config";
 3 | import viteConfig from "./vite.config";
 4 | 
 5 | export default mergeConfig(
 6 |   viteConfig,
 7 |   defineConfig({
 8 |     test: {
 9 |       environment: "happy-dom",
10 |     },
11 |   })
12 | );
13 | 


--------------------------------------------------------------------------------