ioBroker.goodwe-sems
Liest Wechselrichter-, Batterie- und Leistungsflussdaten aus dem GoodWe SEMS Portal (Cloud) - für Installationen, die (z. B. weil kein LAN-Zugang zum Wechselrichter besteht) nicht mit dem lokalen ioBroker.goodwe- Adapter (Modbus/UDP, Port 8899) abgefragt werden können.
Die Anmeldung erfolgt über Ihr gewohntes SEMS-Portal-Konto (dasselbe, das Sie auf semsportal.com bzw. in der SEMS-App verwenden). Ein GoodWe-Organisations-/OpenAPI-Konto ist nicht erforderlich.
Inhaltsverzeichnis
Warum dieser Adapter?
GoodWe ET/EH/BH/BT-Wechselrichter lassen sich normalerweise lokal über Modbus/UDP auslesen (siehe ioBroker.goodwe ). Steht kein LAN-Zugriff auf den Wechselrichter zur Verfügung (z. B. weil nur ein WLAN/LTE-Stick mit dem SEMS-Portal verbunden ist und das Zielnetzwerk anderweitig nicht erreichbar ist), bleibt als einzige Option der Umweg über die Cloud via SEMS-Portal ( GoodWe ), über das die Anlage ohnehin bereits überwacht wird.
API-Ursprung und -Beschränkungen (bitte lesen)
GoodWe bietet offiziell drei APIs an (siehe das technische Dokument zur GoodWe-API ):
- OpenAPI - nur für SEMS -Organisationskonten , Aktivierung durch GoodWe erforderlich.
- Echtzeit-Datenüberwachungs-API – für Drittanbieter, erfordert eine Lizenzvereinbarung sowie eine Geräte-Whitelist.
- Batch-Fernsteuerungsschnittstelle – Kafka-basiert, nur Fernsteuerung.
Keiner dieser Dienste ist mit einem normalen SEMS-Portal-Konto (wie es die meisten Privatanwender haben) zugänglich. Dieser Adapter verwendet stattdessen dieselbe undokumentierte HTTPS-API , die auch die offizielle SEMS-App/Website nutzt (Anmeldung über …).CrossLogin /SEMS+ cross-login , Datenabruf überGetMonitorDetailByPowerstationId Diese Endpunkte wurden von GoodWe nicht für die Nutzung durch Dritte freigegeben oder dokumentiert; die Implementierung basiert auf unabhängiger Verkehrsanalyse sowie den folgenden Open-Source-Referenzprojekten:
Folgen:
- Gut: Wir können die API jederzeit ohne Vorankündigung ändern – der Adapter kann dadurch (vorübergehend) nicht mehr funktionieren.
- Für Drittanbieter existiert kein dokumentierter Echtzeit-/Push-Mechanismus (WebSocket/SignalR).
msgSocketAdrDas Feld taucht zwar in einigen älteren Anmeldeantworten auf, wird aber von keinem der oben genannten Referenzprojekte verwendet. Seine Verwendung wäre reines Reverse Engineering ohne verlässliche Dokumentation und mit einem deutlich höheren Risiko verbunden (Kontosperrung, instabile Verbindung). Dieser Adapter fragt daher bewusst in einem konfigurierbaren Intervall (standardmäßig 5 Minuten) über HTTPS ab, anstatt eine ungetestete WebSocket-Verbindung zu simulieren. - Ein Ratenbegrenzungscode (
GY0429Dies wurde beobachtet (unter anderem in der Dokumentation zur Home Assistant-Integration festgehalten). Der Adapter erkennt diesen Code und pausiert die Anfrage automatisch (standardmäßig 5 Minuten Wartezeit), anstatt das Konto durch wiederholte Anfragen zu gefährden. - Die Nutzung erfolgt auf eigene Gefahr, siehe LICENSE (MIT, keine Gewährleistung).
Felder, die von diesem Endpunkt nicht zurückgegeben werden: Überprüfung anhand einer Live-Antwort tagsüber, dieGetMonitorDetailByPowerstationId Die von diesem Adapter verwendete Gateway-Antwort enthält keinen Stationszeitstempel (info.time ), noch Felder für laufende Einnahmen/Einkommen/Währung (kpi.month_generation ,kpi.day_income ,kpi.total_income ,kpi.currency Die entsprechenden Zustände (Station.PortalTimestamp ,KPI.MonthGeneration ,KPI.TodayIncome ,KPI.TotalIncome ,KPI.Currency Daher werden für kein Konto/keine Tageszeit Datensätze erstellt – es handelt sich um eine permanente Lücke in der Gateway-API selbst, nicht um eine vorübergehende Abwesenheit während Zeiten mit geringer Datengenerierung.PowerFlow.* Zustände werden nur dann erstellt, wenn das Portal tatsächlich Lastflussdaten für das Kraftwerk zurückgibt.
Batteriedaten (optional, experimentell): Der oben genannte Gateway-Endpunkt enthält auch keine Informationen zum Ladezustand/zur Leistung/zur Spannung usw. der Batterie, selbst nicht für Pflanzen, die über eine Batterie verfügen – GoodWes eigenes Webportal (semsplus.goodwe.com ) ruft dies über eine separate , völlig andere, undokumentierte API ab (Sitzung erhalten übercross-login Geräteerkennung überrelatedDevices , Daten über einBAT_SYS Eigenes Gerät vom Typ -telemetry Dieser Endpunkt wurde durch Reverse Engineering ermittelt und Feld für Feld anhand real aufgezeichneten Browserverkehrs (HAR) eines GW8K-ET + LX Batteriesystems verifiziert. Wenn Sie die Option „Batteriedaten abrufen“ in der Instanzkonfiguration aktivieren, ruft der Adapter diese zweite API zusätzlich für jeden Wechselrichter auf, der einen angeschlossenen Endpunkt meldet.BAT_SYS Gerät, unter Verwendung der bereits konfigurierten SEMS-Anmeldeinformationen (keine separate Anmeldung erforderlich) - und erstelltInverters.<sn>.Battery.SOC/Power/Voltage/Current/Temperature/MaxChargeCurrent/MaxDischargeCurrent Die
Diese API ist anfälliger und weniger zuverlässig als der Rest des Adapters : Es handelt sich um eine zweite, unabhängig authentifizierte, undokumentierte und signierte API, die GoodWe ohne Vorwarnung ändern, drosseln oder blockieren kann – völlig unabhängig von der oben genannten Hauptüberwachungs-API. Daher ist sie standardmäßig deaktiviert. Sollte sie ausfallen, ist der Rest des Adapters (PV-Erzeugung, KPIs, Wechselrichter-Telemetrie) nicht beeinträchtigt. Ein Fehler in der Batterietelemetrie wird zwar erkannt und pro Wechselrichter auf Debug-Ebene protokolliert, jedoch nicht ausgelöst.
Installation
Sobald dieser Adapter im offiziellen ioBroker-Adapter-Repository aufgeführt ist, installieren Sie ihn auf die übliche Weise: Admin -> Adapter -> Suche nach "goodwe-sems" -> installieren .
Bis dahin kann ein ioBroker-Administrator es manuell auf dem ioBroker-Host hinzufügen:
iobroker url iobroker.goodwe-sems
Konfiguration
| Feld | Beschreibung |
|---|---|
| SEMS-Konto / Passwort | Die Zugangsdaten sind dieselben wie bei semsportal.com. Das Passwort wird von ioBroker verschlüsselt gespeichert. |
| Pflanzenidentifizierung (optional) | Für die automatische Erkennung leer lassen (GetPowerStationIdByOwner Bei Konten mit mehreren Pflanzen: Kopieren Sie die ID manuell aus der Portal-URL (.../powerstation/powerstatussnmin/<ID> ). |
| Umfrageintervall | Standardmäßig 300 s. Der Adapter erzwingt unabhängig von der Konfiguration ein Minimum von 60 s. |
| Leichtgläubig | Siehe Pushover-Benachrichtigungen . |
Objekt-/Zustandsstruktur
goodwe-sems.0.info.connection SEMS Portal reachable (bool)
goodwe-sems.0.info.lastSuccess Timestamp of the last successful poll
goodwe-sems.0.info.lastError Last error message
goodwe-sems.0.info.consecutiveErrors Number of consecutive failed attempts
goodwe-sems.0.info.rateLimited SEMS Portal is currently rate-limiting (bool)
goodwe-sems.0.info.activePollInterval Currently effective interval incl. backoff (s)
goodwe-sems.0.info.rawResponse Raw JSON response (only when the debug option is enabled)
goodwe-sems.0.Station.Name / .Capacity / .Address / .Latitude / .Longitude / .PortalTimestamp / .Status / .StationId
goodwe-sems.0.KPI.CurrentPower / .TodayGeneration / .MonthGeneration / .TotalGeneration / .TodayIncome / .TotalIncome / .Currency
goodwe-sems.0.PowerFlow.PV / .Load / .Grid / .Battery / .LoadStatus / .GridStatus / .PvStatus / .BatteryStatus
goodwe-sems.0.EVCharger.* (only if reported by the portal)
goodwe-sems.0.Inverters.<serial>.Name / .Model / .Status / .WarningCode
goodwe-sems.0.Inverters.<serial>.CurrentPower / .TodayGeneration / .TotalGeneration / .Temperature
goodwe-sems.0.Inverters.<serial>.PV1..4.Voltage / .Current
goodwe-sems.0.Inverters.<serial>.AC_L1..3.Voltage / .Current / .Frequency
goodwe-sems.0.Inverters.<serial>.Battery.SOC / .Power / .Voltage / .Current / .Temperature / .MaxChargeCurrent / .MaxDischargeCurrent
(only with the "Fetch battery data" option enabled AND an attached battery)
Mit zwei Wechselrichtern (wie in der ursprünglichen Anforderung, für die dieser Adapter entwickelt wurde), zweiInverters.<serial>.* Die Filialen werden automatisch erstellt – die Anzahl ist nicht fest codiert, sondern richtet sich ausschließlich nach den Angaben des Portals für das konfigurierte Konto.
Felder, die das Portal liefert, die diesem Adapter aber (noch) nicht bekannt sind, gehen nicht verloren: Bei aktivierter Debug-Option landet die vollständige Rohantwort iminfo.rawResponse (JSON), sodass es bei Bedarf per Pull Request überprüft und hinzugefügt werden kann.
Fehlerbehandlung, Backoff und Ratenbegrenzungen
- Jeder Abfragezyklus ist vollständig in einen try/catch-Block eingebettet; ein einzelner Fehler kann die Abfrageschleife niemals dauerhaft stoppen.
- Spezielle Fehlerklassen (
SemsAuthError,SemsRateLimitError,SemsNetworkError,SemsProtocolError) gezieltes Verhalten steuern:- Ratenbegrenzung (
GY0429) -> sofortige Pause (Standard 300 s),info.rateLimited = trueDie - Bei einem Anmeldefehler wird ein exponentieller Backoff (maximal 1 Stunde) durchgeführt, um zu verhindern, dass falsche Anmeldeinformationen das Konto zusätzlich belasten.
- Netzwerk-/Protokollfehler -> moderater Backoff.
- Ratenbegrenzung (
- Nach einer konfigurierbaren Anzahl aufeinanderfolgender Ausfälle (Standard: 3) wird die Anlage als "offline" betrachtet und, falls aktiviert, eine Pushover-Benachrichtigung ausgelöst.
- Zusätzlich wird alles strukturiert im ioBroker-Protokoll protokolliert (
error/warn/debug(abhängig vom Schweregrad).
Pushover-Benachrichtigungen
Konfigurierbar in drei Modi:
- Über eine bestehende
ioBroker.pushoverInstanz (sendTo) - empfohlen, keine doppelte Verwaltung von Anmeldeinformationen. - Direkt über die Pushover-API (Ihr eigener Benutzerschlüssel + API-/App-Token, verschlüsselt gespeichert) - funktioniert auch ohne eine separate Pushover-Instanz.
- Beides gleichzeitig.
Ausgelöst durch: SEMS-Anmeldefehler, SEMS-Ratenbegrenzung, längeren Ausfall, unerwarteten Adapterfehler – jeweils einzeln deaktivierbar. Eine interne Wartezeit (standardmäßig 1 Stunde pro Kategorie) verhindert Spam während bestehender Probleme.
Sicherheit und Datenschutz
- Das SEMS-Passwort und das Pushover-API-Token sind als markiert
encryptedNative/protectedNativean der Wurzel vonio-package.jsonund werden von ioBroker verschlüsselt gespeichert, niemals im Klartext protokolliert (der Kontoname wird in den Protokollmeldungen maskiert, z. B.st***@gmail.com). - Der Adapter ermöglicht ausschließlich Lesezugriffe (
GetMonitorDetailByPowerstationId,GetPowerStationIdByOwnerEs gibt bewusst keine Fernsteuerungs-/Schreibfunktion (SaveRemoteControlInverter) - das würde ein deutlich größeres Sicherheits- und Haftungsrisiko darstellen und war nicht Teil der Anforderung. - Keine Drittanbieterabhängigkeit für den HTTP-Zugriff: die integrierte
fetchNode.js >=22 wird anstelle einer zusätzlichen HTTP-Bibliothek verwendet – eine kleinere Angriffsfläche, geringeres Lieferkettenrisiko. - Die von der Login-Antwort zurückgegebene API-Basis-URL wird validiert (nur HTTPS auf Domains im Besitz von GoodWe), bevor sie in weiteren Anfragen verwendet wird. Daher kann eine manipulierte Login-Antwort das Session-Token nicht an einen fremden Host umleiten.
- Alle Netzwerkfehler werden systematisch abgefangen; ungeprüfte Daten aus der API-Antwort werden niemals ausgeführt (
eval,Function, und ähnliche werden nirgendwo verwendet).
Entwicklung
npm install
npm run lint
npm test # unit tests (lib/mapping.js, lib/semsApi.js, lib/notify.js) + package consistency check
Zusätzlich wird vor jeder Veröffentlichung empfohlen:
npx @iobroker/repochecker@latest .
Pull-Anfragen sind willkommen, insbesondere um weitere vom Portal bereitgestellte Felder hinzuzufügen (sieheinfo.rawResponse mit aktivierter Debug-Option) oder um Übersetzungen zu verbessern.
Changelog
1.0.9 (2026-08-26)
- Fix: remove the leftover top-level "Battery" channel that v1.0.8 no longer populates (reported by a tester after updating). Stopped creating it, and added a startup migration that removes it from already-running installations after confirming via getObjectListAsync() that it has no child objects.
1.0.8 (2026-08-25)
- New (opt-in, experimental): battery telemetry via GoodWe's separate, undocumented web-portal API (own login/session, device discovery via relatedDevices(), data via a BAT_SYS device's telemetry() endpoint). Reverse-engineered and verified field-by-field against real captured browser traffic (thanks to a tester's HAR capture!) from a GW8K-ET + LX battery system, including the gateway's SHA-256 signature scheme. Enable "Fetch battery data" to create Inverters..Battery.SOC/Power/Voltage/Current/Temperature/MaxChargeCurrent/MaxDischargeCurrent - uses the same SEMS credentials already configured. Off by default, fully isolated from core monitoring. Also fixed the previous always-empty top-level Battery.SOC/Status states and the guessed-but-wrong per-inverter field names - no migration needed since these states were never actually created.
1.0.7 (2026-08-11)
- Fix E1009: Station.Latitude/Longitude used role "value.gps" (reserved for a combined "lon;lat" string) instead of the correct "value.gps.latitude"/"value.gps.longitude" roles, which support numeric values. Added an explicit startup migration so already-running installations get the corrected role, not just fresh installs.
1.0.6 (2026-08-11)
- Fix both findings from the follow-up review: added a default ("en") for the notificationLanguage select (was blank on fresh installs) and added pushoverUserKey to encryptedNative/protectedNative alongside pushoverApiToken for encryption at rest. No code changes needed - js-controller handles the encryption migration automatically.
1.0.5 (2026-08-09)
- Fix E5005 (false positive): a log message describing why the poll interval was capped contained the literal text "setTimeout(" as part of an explanatory sentence, which the checker's text-based scan flagged as if it were real code. The only actual setTimeout() call in the codebase was already this.setTimeout() (adapter-managed) - verified by running the checker's exact detection regex against every source file. Reworded the log message without changing its meaning. No functional changes.
1.0.4 (2026-08-09)
- Fix E3009 (26 errors from the automated Object Structure Check): the per-inverter AC_L1-3, PV1-4 and Battery sub-groups were missing their required intermediate channel object. _applyMonitorDetail() now ensures a channel for each sub-group that actually has at least one mapped state. No migration needed - these are new objects and self-heal on the next poll cycle after upgrading. Verified against a live daytime API response: 0 missing intermediate objects (was 26). No functional regressions.
1.0.3 (2026-08-09)
- Docs only: documented, based on a live daytime API response, that the SEMS+ gateway endpoint used by this adapter (GetMonitorDetailByPowerstationId) never returns a station timestamp or month-to-date generation/income/currency fields for any account - these are a permanent gap in the API itself, not a symptom of an incomplete/nighttime object dump as previously assumed during review. Battery/PowerFlow states are correctly created only when the portal actually reports that data for the plant. No code changes.
1.0.2 (2026-08-09)
- Fix all findings from the follow-up manual review: translated 6 previously missed German log messages in lib/semsApi.js, fixed a second duplicate German error message, and made _maskAccount() always return English. Implemented proper multi-language support for Pushover notification text (new notificationLanguage config option, English/German, default English). Added a hard ceiling (86400s) on the poll interval to prevent a setTimeout() integer overflow. Corrected the unit of info.activePollInterval from "s" to "sec" as required by the value.interval role. Since js-controller does not reliably re-sync instanceObjects common properties on every adapter update across all versions in the field (see https://github.com/ioBroker/ioBroker.js-controller/issues/769), the unit fix is also applied via an explicit migration on every adapter start, so already-running installations get the corrected value, not just fresh installs. No functional regressions.
1.0.1 (2026-08-08)
- Fix: translated all German log messages to English (this.log.*() calls in main.js, the internal log callback in lib/semsApi.js, and lib/notify.js). The internal Pushover notification log line in Notifier.notify() no longer embeds the (intentionally German-language) push title/message into the log entry. Also translated the underlying SemsAuthError/SemsProtocolError/SemsNetworkError messages to English, since those flow into log lines via error.message. The actual Pushover push notification text intentionally stays German. No functional changes.
1.0.0 (2026-07-22)
- (Stefan Bühler) First stable release: the adapter has been running reliably against the SEMS+ gateway API in production for several release cycles. This release is metadata only - fixed
common.newstranslations for 0.1.15-0.1.19 (some languages were untranslated copies of the English text - flagged by the repochecker as E1144), added a Buy Me a Coffee link next to the PayPal donate badge, and standardized copyright/author metadata. No functional changes.
0.1.19 (2026-07-20)
- (Stefan Bühler) removed the classic, version-prefixed
GetMonitorDetailByPowerstationIdendpoint (tried as/v3,/v2,/v1since 0.1.14/0.1.15) entirely - GoodWe has retired it, every account observed during development 404s on all three versions unconditionally.getMonitorDetail()now calls the SEMS+ gateway API (introduced in 0.1.16) directly, making every poll cycle faster and avoiding pointless failing requests - (Stefan Bühler) fix: the gateway session was never automatically refreshed once it expired server-side - the adapter creates a single long-lived API client at startup and reuses its session indefinitely, and unlike the (now removed) classic path, the gateway request helper never re-logged in on a stale session. This caused the adapter to fail permanently after a few hours (confirmed by a real account: worked in the evening, failed every single poll cycle the entire next day) until manually restarted. Every gateway call now automatically re-logs in once and retries on any error before giving up
- (Stefan Bühler) 5 updated/new regression tests (45 unit tests in total) covering the simplified direct-gateway call and the automatic re-login-and-retry behavior (including giving up correctly after exactly one retry)
0.1.18 (2026-07-19)
- (Stefan Bühler) fix: SEMS+ login still got rejected with
code=C0602 "account_login_abnormal"even after the host fix in 0.1.17, because the adapter identified itself as the iOS app (User-Agent: PVMaster/..., tokenclient: "ios") - but the called endpoint (eu-semsplus.goodwe.com) is, per the real browser capture, only ever used by the SEMS+ web client, sendingclient: "semsPlusWeb", a browser User-Agent, andOrigin/Refererheaders. The login call now builds its own matching header identity for just that one request; every other (classic/legacy) endpoint keeps using the established iOS identity, unchanged - (Stefan Bühler) 1 tightened regression test verifying the login call's client identity and headers
0.1.17 (2026-07-19)
- (Stefan Bühler) fix: SEMS+ login failed for some accounts (
code=C0602 "account_login_abnormal") because the adapter called the global endpoint (semsplus.goodwe.com) instead of the EU-regional one (eu-semsplus.goodwe.com). Confirmed via a real browser HAR capture: the identical request body and password hash succeeded against the regional host. Deliberately implemented without a host-fallback loop - repeatedly retrying the same credentials against multiple hosts looks like credential stuffing to the backend and risks a real account lockout - (Stefan Bühler) the login request now also sends the
x-signatureheader (matching real browser traffic exactly), and a genuine SEMS+ session token is now correctly accepted by the gateway API introduced in 0.1.16 - previously, the gateway fallback only ever received a Legacy-CrossLogin-derived token, which the gateway rejected with the same C0602 error since it isn't a real SEMS+ session - (Stefan Bühler) 1 updated regression test verifying the exact login URL and the presence of the login-time signature header
0.1.16 (2026-07-19)
- (Stefan Bühler) major finding: some accounts whose SEMS+ login is rejected and fall back to the legacy CrossLogin API do not end up on the classic
semsportal.com-style backend at all - they get a session for a completely different, modern microservice API ("SEMS+ gateway",eu-gateway.semsportal.com), which explains whyGetMonitorDetailByPowerstationIdcould never succeed under any of thev1/v2/v3paths tried in 0.1.14/0.1.15. Confirmed via a real account's browser HAR capture (eu-semsplus.goodwe.com) showing the actual endpoints in use (sems-plant/api/stations/...,sems-plant/api/equipments/<sn>/telemetry, etc.) - (Stefan Bühler) the gateway API additionally requires every request to carry a computed
x-signatureheader or it is silently rejected. The signature scheme (base64(sha256(${ts}@${uid}@${token}) + "@" + ts)) was reverse-engineered empirically from ~230 real request/response pairs captured from the web app - 100% match, no exceptions - (Stefan Bühler)
getMonitorDetail()now automatically falls back to this gateway API (station basic info, device list, per-device telemetry/telecounting) when all three classic paths 404, and reshapes the result into the sameinfo/kpi/inverter[]shape the rest of the adapter already expects - no changes needed in the mapping/state-creation layer - (Stefan Bühler) deliberately conservative first version: only fields with a confirmed unit/shape are populated (current power, today's/total generation, per-inverter AC/PV/temperature values); the station-level power-flow split (PV/load/grid/battery) is not populated yet, since every real-account capture so far happened at night and returned an empty object for it
- (Stefan Bühler) 2 new regression tests (47 unit tests in total), including one that verifies the actual signature computation against the real, reverse-engineered formula
0.1.15 (2026-07-19)
- (Stefan Bühler) fix: 0.1.14's v3→v2 fallback for
GetMonitorDetailByPowerstationIdwas insufficient - a real-world account's legacy-login backend returned404 Route Not Foundfor both thev2andv3paths. Community references disagree on which version is correct (pygoodwe hardcodesv2, a separate 2023 write-up usesv1, our own traffic inspection observedv3), sogetMonitorDetail()now tries all three versions in sequence (v3→v2→v1) and uses whichever one doesn't 404 - (Stefan Bühler) diagnostics: debug logs now include the full request URL (including the resolved API base) instead of just the relative path, and the login success log now also prints the resolved API base, making it possible to see exactly which host+path combination is failing
- (Stefan Bühler) 2 updated/new regression tests (45 unit tests in total) covering the three-way version fallback and the case where all three paths fail
0.1.14 (2026-07-19)
- (Stefan Bühler) fix:
GetMonitorDetailByPowerstationIdreturned404 Route Not Foundfor accounts whose SEMS+ login is rejected (observed:code=C0602) and that fall back to the legacy CrossLogin API - that backend serves the endpoint under thev2API path, notv3. Root cause found via a real account's debug log plus the community reference implementation pygoodwe, whose legacy-only client hardcodes thev2path.getMonitorDetail()now triesv3first and automatically retries once withv2on a detected 404, so both backend variants work without any user-facing configuration change - (Stefan Bühler) fix: error messages now also surface the API's
error_msgfield (previously silently dropped, resulting in an uninformative "unbekannter Fehler" even when the response body contained a clear error description) - (Stefan Bühler) 2 new regression tests (44 unit tests in total) covering the v3→v2 fallback and the case where both paths fail
0.1.13 (2026-07-19)
- (Stefan Bühler) diagnostics: log the raw JSON envelope of every SEMS API call at debug level, not just the monitor-detail call. Real-account testing surfaced a
SEMS-API-Fehler: ... GetPowerStationIdByOwner ... unbekannter Fehler (code=undefined)report - the success/error code convention this adapter assumes (code: 0/"0"/"00000") was only ever validated against test fixtures, not this specific endpoint on a live account. This logging is the fastest way to see the actual response shape and fix the real bug without needing access to anyone's SEMS credentials
0.1.12 (2026-07-19)
Further fixes from a repochecker recheck on the ioBroker.repositories listing PR:
- (Stefan Bühler) [E2004] removed the
0.1.10entry fromcommon.newsinio-package.json- that version's CI failed before the deploy step, so it was never actually published to npm - (Stefan Bühler) [S3014] declared
needs: check-and-linton theadapter-testsjob so it only runs after linting succeeds - (Stefan Bühler) [W0066] pinned
@types/nodeto^22(was the open-ended>=22, which could resolve to a newer major with mismatched typings) - (Stefan Bühler) [W4040]/[W4042] fixed the JSON schema associations in
.vscode/settings.json:fileMatchentries must not have a leading slash, and the jsonConfig schema must also matchadmin/jsonCustom.jsonandadmin/jsonTab.json - (Stefan Bühler) [S8913] added
.github/workflows/automerge-dependabot.yml(usingiobroker-bot-orga/action-automerge-dependabot@v1) and.github/auto-merge.ymlso patch updates (and minor updates for dev dependencies) from Dependabot are merged automatically
0.1.11 (2026-07-19)
- (Stefan Bühler) fixed a real CI break introduced in 0.1.10: removed Node.js 20.x from the
adapter-testsmatrix in.github/workflows/test-and-release.yml. It is incompatible withengines.node >=22(also introduced in 0.1.10) once the officialioBroker/testing-action-adapter@v1action runsnpm ciwithengine-strictenabled, which crashed that matrix job and cancelled every other job via fail-fast
0.1.10 (2026-07-19)
Second round of fixes, addressing further findings from a stricter automated @iobroker/repochecker recheck on the ioBroker.repositories listing PR:
- (Stefan Bühler) [W0028] raised
engines.nodeto>=22 - (Stefan Bühler) [W0063] removed
chai,chai-as-promised,mocha,sinonfrom devDependencies (already provided by@iobroker/testing) - (Stefan Bühler) [S0065]/[S0085]/[S0087] added
@types/node,@tsconfig/node22and/tsconfig.jsonfor editor type-checking support - (Stefan Bühler) [S5026] added the
@alcalzone/release-script-plugin-manual-reviewrelease plugin - (Stefan Bühler) [W3013]/[W3015]/[W3017] rewrote
.github/workflows/test-and-release.ymlto use the official sharedioBroker/testing-action-check@v1,ioBroker/testing-action-adapter@v1andioBroker/testing-action-deploy@v1GitHub Actions instead of hand-written steps - (Stefan Bühler) added
test/integration.js(adapter startup smoke test via@iobroker/testing's integration harness) sonpm run test:integrationsucceeds - (Stefan Bühler) [E1032] trimmed
common.newsinio-package.jsonto the 7 entries kept by the repository builder - (Stefan Bühler) [E5512] added the required
sizeproperty to the Pushover section header inadmin/jsonConfig.json - (Stefan Bühler) [S5601] migrated
admin/i18nfrom the long{lang}/translations.jsonformat to the short{lang}.jsonformat - (Stefan Bühler) [S4036] added
.vscode/settings.jsonwith JSON schema associations forio-package.jsonandadmin/jsonConfig.json - (Stefan Bühler) [S8901] added
.github/dependabot.yml(npm + github-actions, weekly, with a cooldown and an@types/nodemajor/minor ignore rule)
0.1.9 (2026-07-19)
Addressed the stricter automated @iobroker/repochecker findings surfaced on the ioBroker.repositories listing PR:
- (Stefan Bühler) [E1057] moved
encryptedNative/protectedNativefromcommonto theio-package.jsonroot, matching the current schema - (Stefan Bühler) [E3009]/[E3010]/[E3011]/[E3012] raised
engines.nodeto>=20,@iobroker/adapter-coreto^3.4.1,js-controllerdependency to>=6.0.11,adminglobalDependency to>=7.6.20 - (Stefan Bühler) [E3040] updated devDependencies (
@iobroker/adapter-dev,@iobroker/testing, mocha, esbuild and others) to current major versions - (Stefan Bühler) [E3000-series] rewrote
.github/workflows/test-and-release.ymlto the current official template: renamed jobs (check-and-lint,adapter-tests,adapter-check,deploy), full OS/Node test matrix (ubuntu/windows/macos x 20/22/24),concurrencygroup, deploy job pinned to Node 24 - (Stefan Bühler) [E5005] replaced global
setTimeout/clearTimeoutwith adapter-managed timers (adapter.setTimeout/adapter.clearTimeout) inlib/notify.jsandlib/semsApi.js - (Stefan Bühler) [E5043] switched to
require("node:crypto") - (Stefan Bühler) [E5507]/[E5510]/[E5512]/[E5612] fixed
admin/jsonConfig.json: added missinglg/xlresponsive sizes on every item, replaced a literal label string with a proper i18n key (loginTab, added to all 11 translation files) - (Stefan Bühler) [E6004]/[E6015]/[W0037]/[W0076] translated
README.mdto English (required language), moved the previous German content toREADME.de.md, addedCHANGELOG_OLD.mdfor older entries - (Stefan Bühler) [W9501] removed the redundant
.npmignore(superseded by package.jsonfiles) - (Stefan Bühler) [E9006] added
.commitinfoto.gitignore - (Stefan Bühler) [S4036]/[S5026] added
prettier.config.mjs, re-formatted the codebase, disabledjsdoc/reject-any-typefor the opaque Node timer-handle type with a justifying comment
0.1.8 (2026-07-19)
Addressed ioBroker adapter-check findings:
- (Stefan Bühler) [E254] removed changelog entries for 0.1.1/0.1.2 - those tags were pushed but their npm-publish CI job failed at the time (missing
NPM_TOKEN/ npm CLI too old for OIDC), so the versions never existed on npm - (Stefan Bühler) [W132] this automatically brought the entry count under the repository builder's 7-entry truncation limit for
common.news - (Stefan Bühler) [W184] removed deprecated
common.title(superseded bycommon.titleLang) and deprecated/ignoredcommon.main(the entry point comes frompackage.json) - (Stefan Bühler) [W034] raised
@iobroker/adapter-corefrom ^3.1.6 to ^3.2.2 - (Stefan Bühler) [W173]/[W174]/[E999]/[W401]:
passwordwas already correctly listed inencryptedNative/protectedNative(verified against the published tarball) - these findings, together with the global axios 404 when fetchingsources-dist-latest.json, are side effects of the adapter not yet being listed in the official ioBroker repository
0.1.7 (2026-07-19)
- (Stefan Bühler) branding: replaced the placeholder icon with the official GoodWe logo (used with permission from GoodWe)
0.1.6 (2026-07-18)
- (Stefan Bühler) updated the dev toolchain: mocha 11, sinon 22, @alcalzone/release-script 5, @iobroker/eslint-config 2; remaining transitive CVEs (adm-zip, diff, esbuild, serialize-javascript) resolved via npm
overrides-npm audit: 0 vulnerabilities (including dev dependencies)
Security/quality audit (security tester, maintainer review, fuzzing of the mapping layer):
- (Stefan Bühler) Security: inverter serial numbers from the (untrusted) portal response are sanitized before becoming part of ioBroker object IDs (prevents broken/unexpectedly nested object trees caused by special characters such as
.*]) - (Stefan Bühler) Security: the API base URL returned by the login server is validated - HTTPS on GoodWe-owned domains only (
*.semsportal.com,*.goodwe.com), otherwise falls back to the known regional URL. A manipulated login response can no longer redirect the session token to a foreign host - (Stefan Bühler) Fix:
null/broken entries in the portal'sinverter[]array crashed the entire poll cycle - now skipped, healthy inverters from the same response are still processed - (Stefan Bühler) Fix: numbers in scientific notation (
"1e5") were parsed incorrectly (yielded 15 instead of 100000) - (Stefan Bühler) Fix: obviously invalid portal timestamps (
99/99/9999 ...) produced absurd epoch values via JavaScript'sDaterollover behaviour - now rejected - (Stefan Bühler) Fix: automatic plant discovery now filters out entries without a usable ID (previously caused permanently failing poll cycles)
- (Stefan Bühler) Robustness: no more state writes after adapter unload; the
adapterErrornotification dedupe window is also reset after recovery - (Stefan Bühler) 14 new regression tests (42 unit tests in total);
npm audit: 0 vulnerabilities in production dependencies (remaining findings were dev-toolchain only)
0.1.5 (2026-07-18)
- (Stefan Bühler) fix: corrected the PayPal donation link in the README (button link instead of the old donate link)
Older changelog entries can be found in CHANGELOG_OLD.md.
License
MIT License
Copyright (c) 2026 Stefan Bühler
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.