From 4a7a1bddf4ef333341e1b0c6384ae7697a94d23f Mon Sep 17 00:00:00 2001 From: Patrick Schurig Date: Tue, 20 Oct 2026 08:49:15 +0200 Subject: [PATCH] =?UTF-8?q?api=20:=20r=C3=A9f=C3=A9rence=20r=C3=A9g=C3=A9n?= =?UTF-8?q?=C3=A9r=C3=A9e=20depuis=20le=20banc=20en=201.15.2+etm71=20(droi?= =?UTF-8?q?ts=20NymeaEnergy.*=20s=C3=A9par=C3=A9s,=20GetOptimizerProtocol)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Le badge PUBLIC de PermissionScopeNone devient AUTH : sur un transport authentifié, nymea exige un token valide pour toute méthode sauf JSONRPC.Hello, Authenticate et RequestPushButtonAuth (jsonrpcserverimplementation.cpp, tag 1.15.2). « Lecture publique, aucun token requis » était faux, en trois langues. Co-Authored-By: Claude Opus 5.5 --- docs/api/index.de.md | 2 +- docs/api/index.en.md | 2 +- docs/api/index.md | 2 +- docs/api/metier/energy.md | 8 ++-- docs/api/metier/integrations.md | 24 +++++------ docs/api/metier/jsonrpc.md | 14 +++---- docs/api/metier/nymeaenergy.md | 65 +++++++++++++++++++---------- docs/api/systeme/configuration.md | 6 +-- docs/api/systeme/users.md | 2 +- docs/integrations/jsonrpc-api.de.md | 2 +- docs/integrations/jsonrpc-api.en.md | 2 +- docs/integrations/jsonrpc-api.md | 2 +- introspect.json | 55 ++++++++++++++---------- scripts/gen_api_reference.py | 4 +- 14 files changed, 109 insertions(+), 81 deletions(-) diff --git a/docs/api/index.de.md b/docs/api/index.de.md index db508f6..ab3c30d 100644 --- a/docs/api/index.de.md +++ b/docs/api/index.de.md @@ -42,7 +42,7 @@ der ETM-Erweiterungen (`Energy`, `AirConditioning`, `EvDash`). | Badge | Scope | Beschreibung | | --- | --- | --- | -| PUBLIC | `PermissionScopeNone` | Öffentlich lesbar, kein Token nötig | +| AUTH | `PermissionScopeNone` | Jedes angemeldete Konto (Token nötig, sobald der Transport Authentifizierung verlangt; nur `JSONRPC.Hello`, `Authenticate` und `RequestPushButtonAuth` gehen ohne) | | CONTROL | `PermissionScopeControlThings` / `ExecuteRules` | Steuerung von Geräten und Regeln | | CONFIGURE | `PermissionScopeConfigureThings` / `ConfigureRules` | Konfiguration | | ADMIN | `PermissionScopeAdmin` | Systemadministration | diff --git a/docs/api/index.en.md b/docs/api/index.en.md index 2eafa37..47deff1 100644 --- a/docs/api/index.en.md +++ b/docs/api/index.en.md @@ -41,7 +41,7 @@ extensions (`Energy`, `AirConditioning`, `EvDash`). | Badge | Scope | Description | | --- | --- | --- | -| PUBLIC | `PermissionScopeNone` | Public read, no token required | +| AUTH | `PermissionScopeNone` | Any authenticated account (token required whenever the transport requires authentication; only `JSONRPC.Hello`, `Authenticate` and `RequestPushButtonAuth` work without one) | | CONTROL | `PermissionScopeControlThings` / `ExecuteRules` | Control of things and rules | | CONFIGURE | `PermissionScopeConfigureThings` / `ConfigureRules` | Configuration | | ADMIN | `PermissionScopeAdmin` | System administration | diff --git a/docs/api/index.md b/docs/api/index.md index 24e481b..0be92cb 100644 --- a/docs/api/index.md +++ b/docs/api/index.md @@ -42,7 +42,7 @@ ETM PowerSync expose l'**API JSON-RPC de nymea** en local, y compris les extensi | Badge | Scope | Description | | --- | --- | --- | -| PUBLIC | `PermissionScopeNone` | Lecture publique, aucun token requis | +| AUTH | `PermissionScopeNone` | Tout compte authentifié (token requis dès que le transport exige l'authentification ; seuls `JSONRPC.Hello`, `Authenticate` et `RequestPushButtonAuth` passent sans) | | CONTROL | `PermissionScopeControlThings` / `ExecuteRules` | Contrôle des appareils et règles | | CONFIGURE | `PermissionScopeConfigureThings` / `ConfigureRules` | Configuration | | ADMIN | `PermissionScopeAdmin` | Administration système | diff --git a/docs/api/metier/energy.md b/docs/api/metier/energy.md index d36f42e..14cb21f 100644 --- a/docs/api/metier/energy.md +++ b/docs/api/metier/energy.md @@ -5,7 +5,7 @@ ### Energy.GetPowerBalance -PUBLIC +AUTH Get the current power balance. That is, production, consumption and acquisition. @@ -30,7 +30,7 @@ _No parameters._ ### Energy.GetPowerBalanceLogs -PUBLIC +AUTH Get logs for the power balance. If from is not give, the log will start at the beginning of recording. If to is not given, the logs will and at the last sample for this sample rate before now. @@ -52,7 +52,7 @@ Get logs for the power balance. If from is not give, the log will start at the b ### Energy.GetRootMeter -PUBLIC +AUTH Get the root meter ID. If there is no root meter set, the params will be empty. @@ -70,7 +70,7 @@ _No parameters._ ### Energy.GetThingPowerLogs -PUBLIC +AUTH Get logs for one or more things power values. If thingIds is not given, logs for all energy related things will be returned. If from is not given, the log will start at the beginning of recording. If to is not given, the logs will and at the last sample for this sample rate before now. If the parameter "includeCurrent" is set to true, the result will contain the newest log entries available, regardless of the sample rate (that is, 1 minute). This may be useful to calculate the difference to the newest entry of the fetched sample rate and the current values to display the live value until the current sample is completed. diff --git a/docs/api/metier/integrations.md b/docs/api/metier/integrations.md index ec1fdcb..372bf1e 100644 --- a/docs/api/metier/integrations.md +++ b/docs/api/metier/integrations.md @@ -30,7 +30,7 @@ Add a new thing to the system. Only things with a setupMethod of SetupMethodJust ### Integrations.BrowseThing -PUBLIC +AUTH Browse a thing. If a ThingClass indicates a thing is browsable, this method will return the BrowserItems. If no parameter besides the thingId is used, the root node of this thingwill be returned. Any returned item which is browsable can be passed as node. Results will be children of the given node. In case of an error during browsing, the error will be indicated and the displayMessage may contain additional information for the user. The displayMessage will be translated. A client UI showing this message to the user should be prepared for empty, but also longer strings. @@ -238,7 +238,7 @@ In case of an error during execution, the error will be indicated and the displa ### Integrations.GetActionTypes -PUBLIC +AUTH Get action types for a specified thingClassId. @@ -258,7 +258,7 @@ Get action types for a specified thingClassId. ### Integrations.GetBrowserItem -PUBLIC +AUTH Get a single item from the browser. This won't give any more info on an item than a regular BrowseThing call, but it allows to fetch details of an item if only the ID is known. In case of an error during browsing, the error will be indicated and the displayMessage may contain additional information for the user. The displayMessage will be translated. A client UI showing this message to the user should be prepared for empty, but also longer strings. @@ -282,7 +282,7 @@ In case of an error during browsing, the error will be indicated and the display ### Integrations.GetEventTypes -PUBLIC +AUTH Get event types for a specified thingClassId. @@ -302,7 +302,7 @@ Get event types for a specified thingClassId. ### Integrations.GetIOConnections -PUBLIC +AUTH Fetch IO connections. Optionally filtered by thingId and stateTypeId. @@ -344,7 +344,7 @@ Get a plugin's params. ### Integrations.GetPlugins -PUBLIC +AUTH Returns a list of loaded plugins. @@ -362,7 +362,7 @@ _No parameters._ ### Integrations.GetStateTypes -PUBLIC +AUTH Get state types for a specified thingClassId. @@ -382,7 +382,7 @@ Get state types for a specified thingClassId. ### Integrations.GetStateValue -PUBLIC +AUTH Get the value of the given thing and the given stateType @@ -404,7 +404,7 @@ Get the value of the given thing and the given stateType ### Integrations.GetStateValues -PUBLIC +AUTH Get all the state values of the given thing. @@ -425,7 +425,7 @@ Get all the state values of the given thing. ### Integrations.GetThingClasses -PUBLIC +AUTH Returns a list of supported thing classes, optionally filtered by vendorId or by a list of thing class ids. @@ -447,7 +447,7 @@ Returns a list of supported thing classes, optionally filtered by vendorId or by ### Integrations.GetThings -PUBLIC +AUTH Returns a list of configured things, optionally filtered by thingId. @@ -468,7 +468,7 @@ Returns a list of configured things, optionally filtered by thingId. ### Integrations.GetVendors -PUBLIC +AUTH Returns a list of supported Vendors. diff --git a/docs/api/metier/jsonrpc.md b/docs/api/metier/jsonrpc.md index adf2982..405dc23 100644 --- a/docs/api/metier/jsonrpc.md +++ b/docs/api/metier/jsonrpc.md @@ -5,7 +5,7 @@ ### JSONRPC.Authenticate -PUBLIC +AUTH Authenticate a client to the api via user & password challenge. Provide a device name which allows the user to identify the client and revoke the token in case the device is lost or stolen. This will return a new token to be used to authorize a client at the API. @@ -53,7 +53,7 @@ Create a new user in the API. This is only allowed to be called when the initial ### JSONRPC.Hello -PUBLIC +AUTH Initiates a connection. Use this method to perform an initial handshake of the connection. Optionally, a parameter "locale" is can be passed to set up the used locale for this connection. Strings such as ThingClass displayNames etc will be localized to this locale. If this parameter is omitted, the default system locale (depending on the configuration) is used. The reply of this method contains information about this core instance such as version information, uuid and its name. The locale valueindicates the locale used for this connection. Note: This method can be called multiple times. The locale used in the last call for this connection will be used. Other values, like initialSetupRequired might change if the setup has been performed in the meantime. The field cacheHashes may contain a map of methods and MD5 hashes. As long as the hash for a method does not change, a client may use a previously cached copy of the call instead of fetching the content again. While the Hello call doesn't necessarily require a token, this can be called with a token. If a token is provided, it will be verified and the reply contains information about the tokens validity and the user and permissions for the given token. @@ -88,7 +88,7 @@ Initiates a connection. Use this method to perform an initial handshake of the c ### JSONRPC.Introspect -PUBLIC +AUTH Introspect this API. @@ -108,7 +108,7 @@ _No parameters._ ### JSONRPC.KeepAlive -PUBLIC +AUTH This is basically a Ping/Pong mechanism a client app may use to check server connectivity. Currently, the server does not actually do anything with this information and will return the call providing the given sessionId back to the caller. It is up to the client whether to use this or not and not required by the server to keep the connection alive. @@ -129,7 +129,7 @@ This is basically a Ping/Pong mechanism a client app may use to check server con ### JSONRPC.RequestPushButtonAuth -PUBLIC +AUTH Authenticate a client to the api via Push Button method. Provide a device name which allows the user to identify the client and revoke the token in case the device is lost or stolen. If push button hardware is available, this will return with success and start listening for push button presses. When the push button is pressed, the PushButtonAuthFinished notification will be sent to the requesting client. The procedure will be cancelled when the connection is interrupted. If another client requests push button authentication while a procedure is still going on, the second call will take over and the first one will be notified by the PushButtonAuthFinished signal about the error. The application should make it clear to the user to not press the button when the procedure fails as this can happen for 2 reasons: a) a second user is trying to auth at the same time and only the currently active user should press the button or b) it might indicate an attacker trying to take over and snooping in for tokens. @@ -150,7 +150,7 @@ Authenticate a client to the api via Push Button method. Provide a device name w ### JSONRPC.SetNotificationStatus -PUBLIC +AUTH Enable/Disable notifications for this connections. Either "enabled" or "namespaces" needs to be given but not both of them. The boolean based "enabled" parameter will enable/disable all notifications at once. If instead the list-based "namespaces" parameter is provided, all given namespaceswill be enabled, the others will be disabled. The return value of "success" will indicate success of the operation. The "enabled" property in the return value is deprecated and used for legacy compatibilty only. It will be set to true if at least one namespace has been enabled. @@ -172,7 +172,7 @@ Enable/Disable notifications for this connections. Either "enabled" or "namespac ### JSONRPC.Version -PUBLIC +AUTH Version of this nymea/JSONRPC interface. diff --git a/docs/api/metier/nymeaenergy.md b/docs/api/metier/nymeaenergy.md index 48396ae..0d177e8 100644 --- a/docs/api/metier/nymeaenergy.md +++ b/docs/api/metier/nymeaenergy.md @@ -45,7 +45,7 @@ Clear the fault latch of a controllable load (ECS-410). Deliberate operator acti ### NymeaEnergy.GetAcquisitionTolerance -CONTROL +AUTH Get the acquisition tolerance. This value will control how much solar surplus is required to start the charging. @@ -63,7 +63,7 @@ _No parameters._ ### NymeaEnergy.GetAvailableSpotMarketProviders -CONTROL +AUTH Get the list of available spot market data providers. @@ -81,7 +81,7 @@ _No parameters._ ### NymeaEnergy.GetBatteryLevelConsideration -ADMIN +AUTH Get the battery level consideration. This value will control how much the energy storage is taking in account @@ -99,7 +99,7 @@ _No parameters._ ### NymeaEnergy.GetChargingInfos -CONTROL +AUTH Get the charging info for all EV chargers, or for a single one when evChargerId is given. An unknown id yields an EMPTY list, never an error: every configured charger has an entry, so an empty list means 'no such charger' and nothing else. @@ -119,7 +119,7 @@ Get the charging info for all EV chargers, or for a single one when evChargerId ### NymeaEnergy.GetChargingSchedules -CONTROL +AUTH Get the planed charging schedules, and whether the L2 degraded mode is currently active (meter silent > 90s, planning suspended). @@ -138,7 +138,7 @@ _No parameters._ ### NymeaEnergy.GetEnergyRatios -CONTROL +AUTH Get the current energy ratios (self-consumption / autonomy) in percent, derived from the energy manager's cumulative counters over the current local day. A rate field is omitted (never null) when not available (denominator <= 0). @@ -160,7 +160,7 @@ _No parameters._ ### NymeaEnergy.GetForecastSite -CONTROL +AUTH Read which site's PV forecast is kept, and which sites COULD be. 'forecastSiteThingId' is omitted when none is designated - a NORMAL state, not a fault. 'candidateSiteThingIds' lists every site with at least one plane publishing a curve; it is what a configuration screen offers. When exactly one candidate exists and nothing has ever been chosen, the engine designates it by itself - designating is not CHOOSING when there is nothing to choose. NOTHING is ever designated automatically: the choice is persisted, and the day a second site appears it would look deliberate when nobody made it. 'fault' carries MISSING_FORECAST_SITE when planes publish but no site is designated - it is ABSENT when no site exists at all, since announcing a missing designation to an installation that has nothing to designate would be an unsatisfiable warning. @@ -181,7 +181,7 @@ _No parameters._ ### NymeaEnergy.GetForecastSnapshot -CONTROL +AUTH The CURRENT PV forecast, read straight from the channel - never from the stored table. GetPvForecast serves the TABLE (history, revisions, reproducible reads); this one serves the DECISION. An arbiter reading the table would read its own trace instead of its input: it would no longer measure, it would re-read itself. 'capturedAt' is when this reply was built. 'contentChangedAt' is when the current content FIRST APPEARED - and it is the one that matters: without it, a FROZEN provider reads as a stable forecast, which is the costliest form of 'silence that looks like a result' since whoever reads it decides to BUY. It is omitted when the store has never seen this content, rather than guessed. 'forecastPoints' is ABSENT when nothing is readable - never a curve of zeros; a missing forecast and a forecast of zero are different statements. 'fault' carries MISSING_FORECAST_SITE (nobody designated a site, and one exists) or FORECAST_PAYLOAD_REFUSED with its cause (the channel publishes something we cannot read). Two faults, two gestures: configure, or look at the provider. With a curve come 'corrections' (physical corrections applied, canonical order: 'temperature' by the provider, 'ac-limit' when the site has an AC limit; empty = raw GTI x kWp x PR; when planes disagree, only the corrections ALL of them received), 'perField' (one entry per summed plane: its thing 'id' and the 'corrections' it declared - where a divergence between planes is read), 'conversion' ('physics' - this engine has no other) and 'acLimitW' when an AC limit is configured: the curve is the sum of the planes CLIPPED to it. ALWAYS (ETM build), whatever the PV outcome: the GRID 'start' (instant), 'resolutionS' and 'steps' - the PV grid when a curve exists (first slot to last, holes included), otherwise hourly from local midnight today to local midnight after tomorrow - and on it, index by index: 'baseload' {model: profile|none, p50W: [W or null], quality} - consumption WITHOUT the controlled loads, median per local slot and day type over 28 days, 'none' with nulls under 7 covered days - and 'price' (null when no tariff is set) {currency, importCtkWh, exportCtkWh, includes, source: fixed|tou, knownUntil}. A slot straddling two tariff zones gets the time-weighted mean. NOTHING here is read by any decision. @@ -214,7 +214,7 @@ _No parameters._ ### NymeaEnergy.GetLoadConfig -CONTROL +AUTH Get the configured controllable loads (etmvariableload). @@ -232,7 +232,7 @@ _No parameters._ ### NymeaEnergy.GetLoadTelemetry -CONTROL +AUTH Get a snapshot of the arbitration runtime state: surplus budget, per-load allocation, availability, fault code, active lock (seconds remaining), mechanism payload and decision reason. Reason and fault are CODES with numeric params - never human-readable sentences: the client renders them in the user's language. Identical payload to the LoadTelemetryChanged notification. 'timestamp' is the end of the last arbitration cycle and is omitted while no cycle has run yet. @@ -255,7 +255,7 @@ _No parameters._ ### NymeaEnergy.GetLockOnUnplug -CONTROL +AUTH Get the lock on unplug setting. @@ -271,9 +271,28 @@ _No parameters._ --- +### NymeaEnergy.GetOptimizerProtocol + +AUTH + +The OpenRPC 1.3 document of the engine <-> optimizer protocol spoken by THIS engine (docs/etm-powersync-optimizer-protocol.openrpc.json, embedded at build time). protocolVersion: the version sent at handshake. schema: the document (methods Handshake, GetPlan, UpdateLearned; components.schemas; x-etm-* extensions for transport, fallback machine and semantic rules). No secret. Static for a given binary: no notification. + +**Parameters:** + +_No parameters._ + +**Returns:** + +| Field | Type | Notes | +| --- | --- | --- | +| `protocolVersion` | `String` | | +| `schema` | `Object` | | + +--- + ### NymeaEnergy.GetOptimizerStatus -CONTROL +AUTH State of the external-optimizer fallback machine (OPTIMIZER_PROTOCOL 7). optimizerExpected: an endpoint is configured. optimizerAlive: the optimizer answered with a valid plan and has not failed two consecutive requests nor lost its connection since. activeStrategy: optimizer | rules | none (none = degraded mode L2, planning suspended). The other fields are for the installer view; an unknown value is OMITTED, never 0. The token is never returned: tokenConfigured only says whether one is set. Same payload as OptimizerStatusChanged. @@ -321,7 +340,7 @@ _No parameters._ ### NymeaEnergy.GetPhasePowerLimit -CONTROL +AUTH Get the phase power consumption limit. 0 if unset. This needs to be set in order for the smart charging to do anything. @@ -339,7 +358,7 @@ _No parameters._ ### NymeaEnergy.GetPlan -CONTROL +AUTH The plan IN FORCE at the last planned cycle. Under an optimizer: the current slot with the power APPLIED by the adapters, then the following slots with the power REQUESTED (informative). Under the rule-based: one slot, strategy rules, and fallbackCode when an optimizer is configured but did not command this cycle. Reasons are codes and params only, never text. inForce is false, and nothing else is returned, before the first cycle and in degraded mode L2 (no plan in force). No notification: read it again on LoadTelemetryChanged or OptimizerStatusChanged. @@ -363,7 +382,7 @@ _No parameters._ ### NymeaEnergy.GetPvForecast -CONTROL +AUTH Read the stored PV production FORECAST for a window. This is a forecast, NEVER a measurement: the conversion ignores shading, soiling, module temperature and inverter clipping - all optimistic - so the curve is a CEILING, systematically above what will be produced. Hours with no forecast are ABSENT, never zero: a zero would read as 'we expect night'. 'knownAt' makes the read reproducible - it returns the curve as it was known at that instant. A revision exists only when the FORECAST CHANGED; the provider's run id does NOT identify the content (it comes from a domain that supplies none of the curve's values), so revisions are keyed on the content itself. 'firstSeenAt' is when this content first appeared - it ORDERS revisions; 'lastSeenAt' is the last time it was republished unchanged - FRESHNESS. Neither is an emission time, and no horizon may be computed from them. The provider blends two model domains, so the FIRST HOURS ARE FRESHER THAN THE REST - a single age cannot date the whole curve, which is why none is published per slot. And beware what a near horizon buys: it reduces the METEOROLOGICAL error, never the CONVERSION bias - shading, soiling, module temperature and inverter clipping are as wrong at three hours as at thirty-six, and all in the optimistic direction. 'Nearer forecast is more reliable' must NOT be shown as 'nearer figure is more accurate'. An UNREADABLE date ('from', 'to' or 'knownAt') is an ERROR, never a window: 'energyError' is EnergyErrorInvalidParameter, 'fault' is FORECAST_DATE_UNREADABLE with 'faultParams.fields' naming the parameters, and 'forecastPoints' is empty and MEANS NOTHING - read 'energyError' first. 'energyError' is EnergyErrorNoError on every successful read. @@ -388,7 +407,7 @@ Read the stored PV production FORECAST for a window. This is a forecast, NEVER a ### NymeaEnergy.GetSpotMarketConfiguration -CONTROL +AUTH Get the current spotmarket configuration. @@ -408,7 +427,7 @@ _No parameters._ ### NymeaEnergy.GetSpotMarketScoreEntries -CONTROL +AUTH Get the current score entries from the current spot market. If spot market is not enabled or not available, the list will be empty. The weighting of the available score entries goes from 0 (worst) to 1.0 (best). @@ -426,7 +445,7 @@ _No parameters._ ### NymeaEnergy.GetTariff -CONTROL +AUTH The tariff entered by the installer. 'zones', 'exportCtkWh' and 'source' (fixed = one zone over 24 h, tou = several) are OMITTED when no tariff is set - never an empty tariff at 0. Ranges are LOCAL wall-clock times of the box, in 'timeZone' (IANA id, always returned): the phone may live in another zone. Prices are FULL prices paid, in c€/kWh incl. taxes ('includes'). Read by no decision. @@ -449,7 +468,7 @@ _No parameters._ ### NymeaEnergy.SetAcquisitionTolerance -CONTROL +CONFIGURE Set the acquisition tolerance for the charging. @@ -509,7 +528,7 @@ Set the charging info for an EV charger. The given object REPLACES the stored on ### NymeaEnergy.SetForecastSite -CONTROL +CONFIGURE Designate the site whose PV forecast is kept. ALL the PV planes under that site are SUMMED - not chosen between: a site's production is physically the sum of its planes, and the curve is superimposed on the MEASURED total. Keeping one plane would put the forecast systematically below the measurement, which reads as an under-performing installation. Planes from DIFFERENT runs are never summed: a partly refreshed roof published as the whole would be a chimera, so the engine waits for the next pass. Pass an empty id to keep no forecast at all. 'acLimitW' is the site's inverter AC limit in W, applied AFTER the sum of the planes. It is the ONE field that is not replaced: OMITTED = UNCHANGED (an older client that ignores it must not clear it each time it saves the site), null = CLEAR the limit, an integer = set it. Declared Variant because nymea refuses null on a Uint; anything but null or an integer is refused. Refused (EnergyErrorInvalidParameter, nothing changed) outside [100, 1000000] W or without a site. Designating no site clears the limit too: a limit has no object without a site. @@ -530,7 +549,7 @@ Designate the site whose PV forecast is kept. ALL the PV planes under that site ### NymeaEnergy.SetLoadConfig -CONTROL +CONFIGURE Replace the full set of controllable load configs. Rejected as a whole (energyError) if any entry is invalid; persisted and applied atomically. @@ -677,7 +696,7 @@ Set the phase power consumption limit. This is the maximum allowed Ampere per ph ### NymeaEnergy.SetSpotMarketConfiguration -CONTROL +CONFIGURE Set the current spotmarket configuration. If enabled, the provideId must be valid. You can get the available providers using GetAvailableSpotMarketProviders. [ETM] The shipped build compiles NO spot market provider (no outbound network flow): enabling is then refused with EnergyErrorInvalidParameter and 'fault' SPOT_MARKET_NOT_IN_BUILD - a code, never a sentence. Disabling is always accepted. @@ -699,7 +718,7 @@ Set the current spotmarket configuration. If enabled, the provideId must be vali ### NymeaEnergy.SetTariff -CONTROL +CONFIGURE Replace the tariff, effective immediately and persisted. One zone covering 00:00-24:00 is a single tariff; several zones are a time-of-use tariff, each with one or more LOCAL ranges [from, to) - a range may cross midnight (22:00-06:00). The ranges must cover the 24 h with NO gap and NO overlap. 'priceCtkWh' >= 0, in c€/kWh incl. taxes (NOT €/kWh). 'exportCtkWh' is the resale price, 0 when omitted. An EMPTY 'zones' clears the tariff. On refusal: EnergyErrorInvalidParameter, 'fault' TARIFF_REFUSED and 'faultParams' {cause, zone?, range?, at?, zones?} - codes and indexes, never a sentence - and NOTHING is changed. diff --git a/docs/api/systeme/configuration.md b/docs/api/systeme/configuration.md index 2b5b559..3494ca3 100644 --- a/docs/api/systeme/configuration.md +++ b/docs/api/systeme/configuration.md @@ -207,7 +207,7 @@ Generate a download entry for an existing configuration backup file. ### Configuration.GetAvailableLanguages -PUBLIC +AUTH Returns a list of locale codes available for the server. i.e. en_US, de_AT @@ -243,7 +243,7 @@ _No parameters._ ### Configuration.GetConfigurations -PUBLIC +AUTH Get all configuration parameters of the server. @@ -303,7 +303,7 @@ _No parameters._ ### Configuration.GetTimeZones -PUBLIC +AUTH Get the list of available timezones. diff --git a/docs/api/systeme/users.md b/docs/api/systeme/users.md index 557b23b..6c4f7ea 100644 --- a/docs/api/systeme/users.md +++ b/docs/api/systeme/users.md @@ -90,7 +90,7 @@ _No parameters._ ### Users.GetUserInfo -PUBLIC +AUTH Get info about the current token (the currently logged in user). diff --git a/docs/integrations/jsonrpc-api.de.md b/docs/integrations/jsonrpc-api.de.md index 7aae3b6..019ee54 100644 --- a/docs/integrations/jsonrpc-api.de.md +++ b/docs/integrations/jsonrpc-api.de.md @@ -44,7 +44,7 @@ Feld `id` (Ganzzahl), um die Antwort zuzuordnen. Benachrichtigungen haben kein ` | Badge | Scope | Beschreibung | | --- | --- | --- | -| PUBLIC | `PermissionScopeNone` | Öffentlich lesbar, kein Token nötig | +| AUTH | `PermissionScopeNone` | Jedes angemeldete Konto (Token nötig, sobald der Transport Authentifizierung verlangt; nur `JSONRPC.Hello`, `Authenticate` und `RequestPushButtonAuth` gehen ohne) | | CONTROL | `PermissionScopeControlThings` / `ExecuteRules` | Steuerung von Geräten und Regeln | | CONFIGURE | `PermissionScopeConfigureThings` / `ConfigureRules` | Konfiguration von Integrationen und Regeln | | ADMIN | `PermissionScopeAdmin` | Systemadministration | diff --git a/docs/integrations/jsonrpc-api.en.md b/docs/integrations/jsonrpc-api.en.md index fe1ad1c..51b4468 100644 --- a/docs/integrations/jsonrpc-api.en.md +++ b/docs/integrations/jsonrpc-api.en.md @@ -44,7 +44,7 @@ Every message is a JSON object terminated by `\n`. Requests carry an `id` field | Badge | Scope | Description | | --- | --- | --- | -| PUBLIC | `PermissionScopeNone` | Public read, no token required | +| AUTH | `PermissionScopeNone` | Any authenticated account (token required whenever the transport requires authentication; only `JSONRPC.Hello`, `Authenticate` and `RequestPushButtonAuth` work without one) | | CONTROL | `PermissionScopeControlThings` / `ExecuteRules` | Control of things and rules | | CONFIGURE | `PermissionScopeConfigureThings` / `ConfigureRules` | Configuration of integrations and rules | | ADMIN | `PermissionScopeAdmin` | System administration | diff --git a/docs/integrations/jsonrpc-api.md b/docs/integrations/jsonrpc-api.md index d2a3b3e..d5fa019 100644 --- a/docs/integrations/jsonrpc-api.md +++ b/docs/integrations/jsonrpc-api.md @@ -43,7 +43,7 @@ Chaque message est un objet JSON terminé par `\n`. Les requêtes incluent un ch | Badge | Scope | Description | | --- | --- | --- | -| PUBLIC | `PermissionScopeNone` | Lecture publique, aucun token requis | +| AUTH | `PermissionScopeNone` | Tout compte authentifié (token requis dès que le transport exige l'authentification ; seuls `JSONRPC.Hello`, `Authenticate` et `RequestPushButtonAuth` passent sans) | | CONTROL | `PermissionScopeControlThings` / `ExecuteRules` | Contrôle des appareils et règles | | CONFIGURE | `PermissionScopeConfigureThings` / `ConfigureRules` | Configuration des intégrations et règles | | ADMIN | `PermissionScopeAdmin` | Administration système | diff --git a/introspect.json b/introspect.json index d401707..beb7987 100644 --- a/introspect.json +++ b/introspect.json @@ -1926,7 +1926,7 @@ "NymeaEnergy.GetAcquisitionTolerance": { "description": "Get the acquisition tolerance. This value will control how much solar surplus is required to start the charging.", "params": {}, - "permissionScope": "PermissionScopeControlThings", + "permissionScope": "PermissionScopeNone", "returns": { "acquisitionTolerance": "Double" } @@ -1934,7 +1934,7 @@ "NymeaEnergy.GetAvailableSpotMarketProviders": { "description": "Get the list of available spot market data providers.", "params": {}, - "permissionScope": "PermissionScopeControlThings", + "permissionScope": "PermissionScopeNone", "returns": { "providers": [ "$ref:SpotMarketProviderInfo" @@ -1944,7 +1944,7 @@ "NymeaEnergy.GetBatteryLevelConsideration": { "description": "Get the battery level consideration. This value will control how much the energy storage is taking in account", "params": {}, - "permissionScope": "PermissionScopeAdmin", + "permissionScope": "PermissionScopeNone", "returns": { "batteryLevelConsideration": "Double" } @@ -1954,7 +1954,7 @@ "params": { "o:evChargerId": "Uuid" }, - "permissionScope": "PermissionScopeControlThings", + "permissionScope": "PermissionScopeNone", "returns": { "chargingInfos": [ "$ref:ChargingInfo" @@ -1964,7 +1964,7 @@ "NymeaEnergy.GetChargingSchedules": { "description": "Get the planed charging schedules, and whether the L2 degraded mode is currently active (meter silent > 90s, planning suspended).", "params": {}, - "permissionScope": "PermissionScopeControlThings", + "permissionScope": "PermissionScopeNone", "returns": { "chargingSchedules": [ "$ref:ChargingSchedule" @@ -1975,7 +1975,7 @@ "NymeaEnergy.GetEnergyRatios": { "description": "Get the current energy ratios (self-consumption / autonomy) in percent, derived from the energy manager's cumulative counters over the current local day. A rate field is omitted (never null) when not available (denominator <= 0).", "params": {}, - "permissionScope": "PermissionScopeControlThings", + "permissionScope": "PermissionScopeNone", "returns": { "measuredSince": "Uint", "o:autonomyRate": "Double", @@ -1987,7 +1987,7 @@ "NymeaEnergy.GetForecastSite": { "description": "Read which site's PV forecast is kept, and which sites COULD be. 'forecastSiteThingId' is omitted when none is designated - a NORMAL state, not a fault. 'candidateSiteThingIds' lists every site with at least one plane publishing a curve; it is what a configuration screen offers. When exactly one candidate exists and nothing has ever been chosen, the engine designates it by itself - designating is not CHOOSING when there is nothing to choose. NOTHING is ever designated automatically: the choice is persisted, and the day a second site appears it would look deliberate when nobody made it. 'fault' carries MISSING_FORECAST_SITE when planes publish but no site is designated - it is ABSENT when no site exists at all, since announcing a missing designation to an installation that has nothing to designate would be an unsatisfiable warning.", "params": {}, - "permissionScope": "PermissionScopeControlThings", + "permissionScope": "PermissionScopeNone", "returns": { "candidateSiteThingIds": [ "Uuid" @@ -2000,7 +2000,7 @@ "NymeaEnergy.GetForecastSnapshot": { "description": "The CURRENT PV forecast, read straight from the channel - never from the stored table. GetPvForecast serves the TABLE (history, revisions, reproducible reads); this one serves the DECISION. An arbiter reading the table would read its own trace instead of its input: it would no longer measure, it would re-read itself. 'capturedAt' is when this reply was built. 'contentChangedAt' is when the current content FIRST APPEARED - and it is the one that matters: without it, a FROZEN provider reads as a stable forecast, which is the costliest form of 'silence that looks like a result' since whoever reads it decides to BUY. It is omitted when the store has never seen this content, rather than guessed. 'forecastPoints' is ABSENT when nothing is readable - never a curve of zeros; a missing forecast and a forecast of zero are different statements. 'fault' carries MISSING_FORECAST_SITE (nobody designated a site, and one exists) or FORECAST_PAYLOAD_REFUSED with its cause (the channel publishes something we cannot read). Two faults, two gestures: configure, or look at the provider. With a curve come 'corrections' (physical corrections applied, canonical order: 'temperature' by the provider, 'ac-limit' when the site has an AC limit; empty = raw GTI x kWp x PR; when planes disagree, only the corrections ALL of them received), 'perField' (one entry per summed plane: its thing 'id' and the 'corrections' it declared - where a divergence between planes is read), 'conversion' ('physics' - this engine has no other) and 'acLimitW' when an AC limit is configured: the curve is the sum of the planes CLIPPED to it. ALWAYS (ETM build), whatever the PV outcome: the GRID 'start' (instant), 'resolutionS' and 'steps' - the PV grid when a curve exists (first slot to last, holes included), otherwise hourly from local midnight today to local midnight after tomorrow - and on it, index by index: 'baseload' {model: profile|none, p50W: [W or null], quality} - consumption WITHOUT the controlled loads, median per local slot and day type over 28 days, 'none' with nulls under 7 covered days - and 'price' (null when no tariff is set) {currency, importCtkWh, exportCtkWh, includes, source: fixed|tou, knownUntil}. A slot straddling two tariff zones gets the time-weighted mean. NOTHING here is read by any decision.", "params": {}, - "permissionScope": "PermissionScopeControlThings", + "permissionScope": "PermissionScopeNone", "returns": { "capturedAt": "String", "o:acLimitW": "Uint", @@ -2043,7 +2043,7 @@ "NymeaEnergy.GetLoadConfig": { "description": "Get the configured controllable loads (etmvariableload).", "params": {}, - "permissionScope": "PermissionScopeControlThings", + "permissionScope": "PermissionScopeNone", "returns": { "loadConfigs": [ "$ref:LoadConfig" @@ -2053,7 +2053,7 @@ "NymeaEnergy.GetLoadTelemetry": { "description": "Get a snapshot of the arbitration runtime state: surplus budget, per-load allocation, availability, fault code, active lock (seconds remaining), mechanism payload and decision reason. Reason and fault are CODES with numeric params - never human-readable sentences: the client renders them in the user's language. Identical payload to the LoadTelemetryChanged notification. 'timestamp' is the end of the last arbitration cycle and is omitted while no cycle has run yet.", "params": {}, - "permissionScope": "PermissionScopeControlThings", + "permissionScope": "PermissionScopeNone", "returns": { "degradedMode": "Bool", "loads": [ @@ -2127,15 +2127,24 @@ "NymeaEnergy.GetLockOnUnplug": { "description": "Get the lock on unplug setting.", "params": {}, - "permissionScope": "PermissionScopeControlThings", + "permissionScope": "PermissionScopeNone", "returns": { "lockOnUnplug": "Bool" } }, + "NymeaEnergy.GetOptimizerProtocol": { + "description": "The OpenRPC 1.3 document of the engine <-> optimizer protocol spoken by THIS engine (docs/etm-powersync-optimizer-protocol.openrpc.json, embedded at build time). protocolVersion: the version sent at handshake. schema: the document (methods Handshake, GetPlan, UpdateLearned; components.schemas; x-etm-* extensions for transport, fallback machine and semantic rules). No secret. Static for a given binary: no notification.", + "params": {}, + "permissionScope": "PermissionScopeNone", + "returns": { + "protocolVersion": "String", + "schema": "Object" + } + }, "NymeaEnergy.GetOptimizerStatus": { "description": "State of the external-optimizer fallback machine (OPTIMIZER_PROTOCOL 7). optimizerExpected: an endpoint is configured. optimizerAlive: the optimizer answered with a valid plan and has not failed two consecutive requests nor lost its connection since. activeStrategy: optimizer | rules | none (none = degraded mode L2, planning suspended). The other fields are for the installer view; an unknown value is OMITTED, never 0. The token is never returned: tokenConfigured only says whether one is set. Same payload as OptimizerStatusChanged.", "params": {}, - "permissionScope": "PermissionScopeControlThings", + "permissionScope": "PermissionScopeNone", "returns": { "activeStrategy": "String", "o:capabilities": { @@ -2173,7 +2182,7 @@ "NymeaEnergy.GetPhasePowerLimit": { "description": "Get the phase power consumption limit. 0 if unset. This needs to be set in order for the smart charging to do anything.", "params": {}, - "permissionScope": "PermissionScopeControlThings", + "permissionScope": "PermissionScopeNone", "returns": { "phasePowerLimit": "Uint" } @@ -2181,7 +2190,7 @@ "NymeaEnergy.GetPlan": { "description": "The plan IN FORCE at the last planned cycle. Under an optimizer: the current slot with the power APPLIED by the adapters, then the following slots with the power REQUESTED (informative). Under the rule-based: one slot, strategy rules, and fallbackCode when an optimizer is configured but did not command this cycle. Reasons are codes and params only, never text. inForce is false, and nothing else is returned, before the first cycle and in degraded mode L2 (no plan in force). No notification: read it again on LoadTelemetryChanged or OptimizerStatusChanged.", "params": {}, - "permissionScope": "PermissionScopeControlThings", + "permissionScope": "PermissionScopeNone", "returns": { "inForce": "Bool", "o:computedAt": "String", @@ -2215,7 +2224,7 @@ "o:knownAt": "String", "to": "String" }, - "permissionScope": "PermissionScopeControlThings", + "permissionScope": "PermissionScopeNone", "returns": { "energyError": "$ref:EnergyError", "forecastPoints": [ @@ -2233,7 +2242,7 @@ "NymeaEnergy.GetSpotMarketConfiguration": { "description": "Get the current spotmarket configuration.", "params": {}, - "permissionScope": "PermissionScopeControlThings", + "permissionScope": "PermissionScopeNone", "returns": { "available": "Bool", "enabled": "Bool", @@ -2243,7 +2252,7 @@ "NymeaEnergy.GetSpotMarketScoreEntries": { "description": "Get the current score entries from the current spot market. If spot market is not enabled or not available, the list will be empty. The weighting of the available score entries goes from 0 (worst) to 1.0 (best).", "params": {}, - "permissionScope": "PermissionScopeControlThings", + "permissionScope": "PermissionScopeNone", "returns": { "spotMarketScoreEntries": [ "$ref:ScoreEntry" @@ -2253,7 +2262,7 @@ "NymeaEnergy.GetTariff": { "description": "The tariff entered by the installer. 'zones', 'exportCtkWh' and 'source' (fixed = one zone over 24 h, tou = several) are OMITTED when no tariff is set - never an empty tariff at 0. Ranges are LOCAL wall-clock times of the box, in 'timeZone' (IANA id, always returned): the phone may live in another zone. Prices are FULL prices paid, in c\u20ac/kWh incl. taxes ('includes'). Read by no decision.", "params": {}, - "permissionScope": "PermissionScopeControlThings", + "permissionScope": "PermissionScopeNone", "returns": { "currency": "String", "includes": [ @@ -2281,7 +2290,7 @@ "params": { "acquisitionTolerance": "Double" }, - "permissionScope": "PermissionScopeControlThings", + "permissionScope": "PermissionScopeConfigureThings", "returns": { "energyError": "$ref:EnergyError" } @@ -2312,7 +2321,7 @@ "o:acLimitW": "Variant", "o:forecastSiteThingId": "Uuid" }, - "permissionScope": "PermissionScopeControlThings", + "permissionScope": "PermissionScopeConfigureThings", "returns": { "energyError": "$ref:EnergyError" } @@ -2366,7 +2375,7 @@ } ] }, - "permissionScope": "PermissionScopeControlThings", + "permissionScope": "PermissionScopeConfigureThings", "returns": { "energyError": "$ref:EnergyError" } @@ -2444,7 +2453,7 @@ "enabled": "Bool", "o:providerId": "Uuid" }, - "permissionScope": "PermissionScopeControlThings", + "permissionScope": "PermissionScopeConfigureThings", "returns": { "energyError": "$ref:EnergyError", "o:fault": "String" @@ -2467,7 +2476,7 @@ } ] }, - "permissionScope": "PermissionScopeControlThings", + "permissionScope": "PermissionScopeConfigureThings", "returns": { "energyError": "$ref:EnergyError", "o:fault": "String", diff --git a/scripts/gen_api_reference.py b/scripts/gen_api_reference.py index b2ace0b..1fe33bc 100644 --- a/scripts/gen_api_reference.py +++ b/scripts/gen_api_reference.py @@ -49,7 +49,7 @@ NS_SYSTEM = set(NS_SYSTEM_ORDER) PERM_BADGES: dict[str, str] = { "PermissionScopeNone": - 'PUBLIC', + 'AUTH', "PermissionScopeControlThings": 'CONTROL', "PermissionScopeExecuteRules": @@ -422,7 +422,7 @@ ETM PowerSync expose l'**API JSON-RPC de nymea** en local, y compris les extensi | Badge | Scope | Description | | --- | --- | --- | -| PUBLIC | `PermissionScopeNone` | Lecture publique, aucun token requis | +| AUTH | `PermissionScopeNone` | Tout compte authentifié (token requis dès que le transport exige l'authentification ; seuls `JSONRPC.Hello`, `Authenticate` et `RequestPushButtonAuth` passent sans) | | CONTROL | `PermissionScopeControlThings` / `ExecuteRules` | Contrôle des appareils et règles | | CONFIGURE | `PermissionScopeConfigureThings` / `ConfigureRules` | Configuration | | ADMIN | `PermissionScopeAdmin` | Administration système |