From fc86ff7ade15dc92f0970dcbb1febab803390fd7 Mon Sep 17 00:00:00 2001 From: Torben Woltjen Date: Thu, 16 Feb 2023 10:39:43 +0100 Subject: [PATCH 01/19] Fix typos in German localisation and change some words to more common one MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In German, you bascially never can have two nouns after each other, just separated by a space. Either you write them together (Dampfschifffahrtsgesellschaftskapitän) or in case one of them is a foreign word, you *can* but don't have to separate them by a hyphen (Firmware-Aktualisierung). Additionally, I've changed some more details like WiFi -> WLAN, because that is a lot more common in German. I've also removed the "-Einstellungen" from the settings dropdown, because having it on every single item just makes it less readable (especially considerung the dropdown itself already is called "Einstellungen", so it's clear, all those items are for settings) (now it does work out the same way as the Info dropdown) --- webapp/src/locales/de.json | 200 ++++++++++++++++++------------------- 1 file changed, 100 insertions(+), 100 deletions(-) diff --git a/webapp/src/locales/de.json b/webapp/src/locales/de.json index 711ffedd..864fa648 100644 --- a/webapp/src/locales/de.json +++ b/webapp/src/locales/de.json @@ -1,17 +1,17 @@ { "menu": { - "LiveView": "Live Ansicht", + "LiveView": "Live-Ansicht", "Settings": "Einstellungen", - "NetworkSettings": "Netzwerk Einstellungen", - "NTPSettings": "NTP Einstellungen", - "MQTTSettings": "MQTT Einstellungen", - "InverterSettings": "Wechselrichter Einstellungen", - "SecuritySettings": "Sicherheitseinstellungen", - "DTUSettings": "DTU Einstellungen", - "DeviceManager": "Geräte-Manager", + "NetworkSettings": "Netzwerk", + "NTPSettings": "NTP", + "MQTTSettings": "MQTT", + "InverterSettings": "Wechselrichter", + "SecuritySettings": "Sicherheit", + "DTUSettings": "DTU", + "DeviceManager": "Hardware", "ConfigManagement": "Konfigurationsverwaltung", - "FirmwareUpgrade": "Firmware Aktualisierung", - "DeviceReboot": "Geräteneustart", + "FirmwareUpgrade": "Firmware-Aktualisierung", + "DeviceReboot": "Neustart", "Info": "Info", "System": "System", "Network": "Netzwerk", @@ -50,7 +50,7 @@ "5004": "Ungültigen Inverter angegeben!", "6001": "Neustart durchgeführt!", "6002": "Neustart abgebrochen!", - "7001": "MQTT Server muss zwischen 1 und {max} Zeichen lang sein!", + "7001": "MQTT-Server muss zwischen 1 und {max} Zeichen lang sein!", "7002": "Benutzername darf nicht länger als {max} Zeichen sein!", "7003": "Passwort darf nicht länger als {max} Zeichen sein!", "7004": "Topic darf nicht länger als {max} Zeichen sein!", @@ -58,18 +58,18 @@ "7006": "Topic muss mit einem Slash (/) enden!", "7007": "Port muss eine Zahl zwischen 1 und 65535 sein!", "7008": "Das Zertifikat darf nicht länger als {max} Zeichen sein!", - "7009": "LWT Topic darf nicht länger als {max} Zeichen sein!", - "7010": "LWT Topic darf keine Leerzeichen enthalten!", - "7011": "LWT Online Nachricht darf nicht länger als {max} Zeichen sein!", - "7012": "LWT Offline Nachricht darf nicht länger als {max} Zeichen sein!", + "7009": "LWT-Topic darf nicht länger als {max} Zeichen sein!", + "7010": "LWT-Topic darf keine Leerzeichen enthalten!", + "7011": "LWT-Online-Nachricht darf nicht länger als {max} Zeichen sein!", + "7012": "LWT-Offline-Nachricht darf nicht länger als {max} Zeichen sein!", "7013": "Veröffentlichungsintervall muss zwischen {min} und {max} sein!", - "7014": "Hass Topic darf nicht länger als {max} Zeichen sein!", - "7015": "Hass Topic darf keine Leerzeichen enthalten!", - "8001": "IP Adresse ist ungültig!", + "7014": "Hass-Topic darf nicht länger als {max} Zeichen sein!", + "7015": "Hass-Topic darf keine Leerzeichen enthalten!", + "8001": "IP-Adresse ist ungültig!", "8002": "Netzmaske ist ungültig!", "8003": "Standardgateway ist ungültig!", - "8004": "DNS Server IP 1 ist ungültig!", - "8005": "DNS Server IP 2 ist ungültig!", + "8004": "DNS-Server-IP 1 ist ungültig!", + "8005": "DNS-Server-IP 2 ist ungültig!", "9001": "Zeitserver muss zwischen 1 und {max} Zeichen lang sein!", "9002": "Zeitzone muss zwischen 1 und {max} Zeichen lang sein!", "9003": "Zeitzonenbeschreibung muss zwischen 1 und {max} Zeichen lang sein!", @@ -87,28 +87,28 @@ "12001": "Profil muss zwischen 1 und {max} Zeichen lang sein!" }, "home": { - "LiveData": "Live Daten", + "LiveData": "Live-Daten", "SerialNumber": "Seriennummer: ", "CurrentLimit": "Aktuelles Limit: ", - "DataAge": "letzte Aktualisierung: ", + "DataAge": "Letzte Aktualisierung: ", "Seconds": "vor {val} Sekunden", "ShowSetInverterLimit": "Zeige / Setze Wechselrichterlimit", "TurnOnOff": "Schalte Wechselrichter ein oder aus", - "ShowInverterInfo": "Zeige Wechselrichter Informationen", + "ShowInverterInfo": "Zeige Wechselrichter-Informationen", "ShowEventlog": "Zeige Ereignisanzeige", "UnreadMessages": "Ungelesene Meldungen", "Loading": "@:base.Loading", "EventLog": "Ereignisanzeige", "Close": "Schließen", - "InverterInfo": "Wechselrichter Informationen", - "LimitSettings": "Limit Einstellungen", + "InverterInfo": "Wechselrichter-Informationen", + "LimitSettings": "Limit-Einstellungen", "LastLimitSetStatus": "Letzter Übertragungsstatus:", "SetLimit": "Setze Limit:", "Relative": "Relativ (%)", "Absolute": "Absolut (W)", "LimitHint": "Hinweis: Wenn das Limit als Absolutwert eingestellt wird, wird die Anzeige des aktuellen Wertes erst nach ~4 Minuten aktualisiert.", "SetPersistent": "Limit dauerhaft setzen", - "SetNonPersistent": "Limit nicht dauerhaft setzen", + "SetNonPersistent": "Limit temporär setzen", "PowerSettings": "Energieeinstellungen", "LastPowerSetStatus": "Letzer Übertragungsstatus:", "TurnOn": "Einschalten", @@ -128,14 +128,14 @@ "devinfo": { "NoInfo": "Keine Informationen verfügbar", "NoInfoLong": "Bisher wurden noch keine gültigen Daten vom Wechselrichter empfangen. Versuche es weiter...", - "UnknownModel": "Unbekanntes Modell! Bitte melden Sie die \"Hardware Teilenummer\" und das Modell (z.B. HM-350) als Problem hier.", + "UnknownModel": "Unbekanntes Modell! Bitte melden Sie die \"Hardware Teilenummer\" und das Modell (z.B. HM-350) hier als Problem.", "Model": "Modell", "DetectedMaxPower": "Ermittelte max. Leistung", - "BootloaderVersion": "Bootloader Version", - "FirmwareVersion": "Firmware Version", - "FirmwareBuildDate": "Firmware Erstellungsdatum", - "HardwarePartNumber": "Hardware Teilenummer", - "HardwareVersion": "Hardware Version" + "BootloaderVersion": "Bootloader-Version", + "FirmwareVersion": "Firmware-Version", + "FirmwareBuildDate": "Firmware-Erstellungsdatum", + "HardwarePartNumber": "Hardware-Teilenummer", + "HardwareVersion": "Hardware-Version" }, "systeminfo": { "SystemInfo": "System Informationen", @@ -144,13 +144,13 @@ "VersionOk": "Aktuell!" }, "firmwareinfo": { - "FirmwareInformation": "Firmware Informationen", + "FirmwareInformation": "Firmwareinformationen", "Hostname": "Hostname", - "SdkVersion": "SDK Version", + "SdkVersion": "SDK-Version", "ConfigVersion": "Konfigurationsversion", - "FirmwareVersion": "Firmware Version / Git Hash", + "FirmwareVersion": "Firmwareversion / git Hash", "FirmwareVersionHint": "Klicken Sie hier, um Informationen über Ihre aktuelle Version anzuzeigen", - "FirmwareUpdate": "Firmware Aktualisierung", + "FirmwareUpdate": "Firmware-Aktualisierung", "FirmwareUpdateHint": "Klicken Sie hier, um die Änderungen zwischen Ihrer Version und der neuesten Version anzuzeigen", "ResetReason0": "Reset Grund CPU 0", "ResetReason1": "Reset Grund CPU 1", @@ -158,15 +158,15 @@ "Uptime": "Betriebszeit" }, "hardwareinfo": { - "HardwareInformation": "Hardware Informationen", - "ChipModel": "Chip Modell", - "ChipRevision": "Chip Revision", - "ChipCores": "Chip Kerne", - "CpuFrequency": "CPU Frequenz", + "HardwareInformation": "Hardwareinformationen", + "ChipModel": "Chip-Modell", + "ChipRevision": "Chip-Revision", + "ChipCores": "Chip-Kerne", + "CpuFrequency": "CPU-Frequenz", "Mhz": "MHz" }, "memoryinfo": { - "MemoryInformation": "Speicher Informationen", + "MemoryInformation": "Speicherinformationen", "Type": "Typ", "Usage": "Verwendung", "Free": "Frei", @@ -177,18 +177,18 @@ "Sketch": "Sketch" }, "radioinfo": { - "RadioInformation": "Funkmodul Informationen", - "ChipStatus": "Chip Status", - "ChipType": "Chip Typ", + "RadioInformation": "Funkmodulinformationen", + "ChipStatus": "Chip-Status", + "ChipType": "Chip-Typ", "Connected": "verbunden", "NotConnected": "nicht verbunden", "Unknown": "unbekannt" }, "networkinfo": { - "NetworkInformation": "Netzwerk Informationen" + "NetworkInformation": "Netzwerkinformationen" }, "wifistationinfo": { - "WifiStationInfo": "WiFi Informationen (Station)", + "WifiStationInfo": "WLAN-Informationen (Station)", "Status": "Status", "Enabled": "aktiv", "Disabled": "nicht aktiv", @@ -197,7 +197,7 @@ "Rssi": "RSSI" }, "wifiapinfo": { - "WifiApInfo": "WiFi Informationen (Access Point)", + "WifiApInfo": "WLAN-Informationen (Access Point)", "Status": "@:wifistationinfo.Status", "Enabled": "@:wifistationinfo.Enabled", "Disabled": "@:wifistationinfo.Disabled", @@ -205,21 +205,21 @@ "Stations": "# Teilnehmer" }, "interfacenetworkinfo": { - "NetworkInterface": "Netzwerk Schnittstelle ({iface})", + "NetworkInterface": "Netzwerkschnittstelle ({iface})", "Hostname": "@:firmwareinfo.Hostname", - "IpAddress": "IP Adresse", + "IpAddress": "IP-Adresse", "Netmask": "Netzmaske", "DefaultGateway": "Standardgateway", "Dns": "DNS {num}", - "MacAddress": "MAC Adresse" + "MacAddress": "MAC-Adresse" }, "interfaceapinfo": { - "NetworkInterface": "Netzwerk Schnittstelle (Access Point)", + "NetworkInterface": "Netzwerkschnittstelle (Access Point)", "IpAddress": "@:interfacenetworkinfo.IpAddress", "MacAddress": "@:interfacenetworkinfo.MacAddress" }, "ntpinfo": { - "NtpInformation": "NTP Informationen", + "NtpInformation": "NTP-Informationen", "ConfigurationSummary": "Konfigurationszusammenfassung", "Server": "Server", "Timezone": "Zeitzone", @@ -231,7 +231,7 @@ "LocalTime": "Lokale Uhrzeit" }, "mqttinfo": { - "MqttInformation": "MQTT Informationen", + "MqttInformation": "MQTT-Informationen", "ConfigurationSummary": "@:ntpinfo.ConfigurationSummary", "Status": "@:ntpinfo.Status", "Enabled": "aktiv", @@ -245,7 +245,7 @@ "Retain": "Retain", "Tls": "TLS", "RootCertifcateInfo": "Root CA-Zertifikat-Informationen", - "HassSummary": "Home Assistant MQTT Auto Discovery Konfigurationszusammenfassung", + "HassSummary": "Home Assistant MQTT-Auto-Discovery Konfigurationszusammenfassung", "Expire": "Ablaufen", "IndividualPanels": "Einzelne Paneele", "RuntimeSummary": "Laufzeitzusammenfassung", @@ -255,7 +255,7 @@ }, "console": { "Console": "Konsole", - "VirtualDebugConsole": "Virtuelle Debug Konsole", + "VirtualDebugConsole": "Virtuelle Debug-Konsole", "EnableAutoScroll": "Automatisches Scrollen aktivieren", "ClearConsole": "Konsole löschen", "CopyToClipboard": "In die Zwischenablage kopieren" @@ -277,7 +277,7 @@ "Power": "Leistung", "Voltage": "Spannung", "Current": "Strom", - "Power DC": "DC Leistung", + "Power DC": "DC-Leistung", "YieldDay": "Tagesertrag", "YieldTotal": "Gesamtertrag", "Frequency": "Frequenz", @@ -297,11 +297,11 @@ "RebootHint": "Hinweis: Ein manueller Neustart muss normalerweise nicht durchgeführt werden. OpenDTU führt jeden erforderlichen Neustart (z. B. nach einem Firmware-Update) automatisch durch. Einstellungen werden auch ohne Neustart übernommen. Wenn Sie aufgrund eines Fehlers einen Neustart durchführen müssen, denken Sie bitte daran, diesen unter https://github.com/tbnobody/OpenDTU/issues zu melden." }, "dtuadmin": { - "DtuSettings": "DTU Einstellungen", - "DtuConfiguration": "DTU Konfiguration", + "DtuSettings": "DTU-Einstellungen", + "DtuConfiguration": "DTU-Konfiguration", "Serial": "Seriennummer:", "SerialHint": "Sowohl der Wechselrichter als auch die DTU haben eine Seriennummer. Die DTU-Seriennummer wird beim ersten Start zufällig generiert und muss normalerweise nicht geändert werden.", - "PollInterval": "Abfrageinterval:", + "PollInterval": "Abfrageintervall:", "Seconds": "Sekunden", "PaLevel": "Sendeleistung:", "PaLevelHint": "Stellen Sie sicher, dass Ihre Stromversorgung stabil genug ist, bevor Sie die Sendeleistung erhöhen.", @@ -313,71 +313,71 @@ }, "securityadmin": { "SecuritySettings": "Sicherheitseinstellungen", - "AdminPassword": "Administrator Passwort", + "AdminPassword": "Administrator-Passwort", "Password": "Passwort:", "RepeatPassword": "Passwort wiederholen:", - "PasswordHint": "Hinweis: Das Administrator-Passwort wird für den Zugriff auf die Webschnittstelle (Benutzer 'admin'), aber auch für die Verbindung mit dem Gerät im AP-Modus verwendet. Es muss 8..64 Zeichen lang sein.", + "PasswordHint": "Hinweis: Das Administrator-Passwort wird für den Zugriff auf die Webschnittstelle (Benutzer 'admin'), aber auch für die Verbindung mit dem Gerät im AP-Modus verwendet. Es muss zwischen 8 und 64 Zeichen lang sein.", "Permissions": "Berechtigungen", "ReadOnly": "Nur-Lese-Zugriff auf die Weboberfläche ohne Passwort zulassen", "Save": "@:dtuadmin.Save" }, "ntpadmin": { - "NtpSettings": "NTP Einstellungen", - "NtpConfiguration": "NTP Konfiguration", + "NtpSettings": "NTP-Einstellungen", + "NtpConfiguration": "NTP-Konfiguration", "TimeServer": "Zeitserver:", "TimeServerHint": "Der Standardwert ist in Ordnung, solange OpenDTU direkten Zugang zum Internet hat.", "Timezone": "Zeitzone:", "TimezoneConfig": "Zeitzonenkonfiguration:", "Save": "@:dtuadmin.Save", "ManualTimeSynchronization": "Manuelle Zeitsynchronization", - "CurrentOpenDtuTime": "Aktuelle OpenDTU Zeit:", + "CurrentOpenDtuTime": "Aktuelle OpenDTU-Zeit:", "CurrentLocalTime": "Aktuelle lokale Zeit:", "SynchronizeTime": "Zeit synchronisieren", "SynchronizeTimeHint": "Hinweis: Sie können die manuelle Zeitsynchronisation verwenden, um die aktuelle Zeit von OpenDTU einzustellen, wenn kein NTP-Server verfügbar ist. Beachten Sie aber, dass im Falle eines Stromausfalls die Zeit verloren geht. Beachten Sie auch, dass die Zeitgenauigkeit stark verzerrt wird, da sie nicht regelmäßig neu synchronisiert werden kann und der ESP32-Mikrocontroller nicht über eine Echtzeituhr verfügt." }, "networkadmin": { - "NetworkSettings": "Netzwerk Einstellungen", - "WifiConfiguration": "WiFi Konfiguration", - "WifiSsid": "WiFi SSID:", - "WifiPassword": "WiFi Passwort:", + "NetworkSettings": "Netzwerkeinstellungen", + "WifiConfiguration": "WLAN-Konfiguration", + "WifiSsid": "WLAN-SSID:", + "WifiPassword": "WLAN-Passwort:", "Hostname": "Hostname:", "HostnameHint": "Hinweis: Der Text %06X wird durch die letzten 6 Ziffern der ESP-ChipID im Hex-Format ersetzt.", "EnableDhcp": "DHCP aktivieren", - "StaticIpConfiguration": "Statische IP Konfiguration", - "IpAddress": "IP Adresse:", + "StaticIpConfiguration": "Statische IP-Konfiguration", + "IpAddress": "IP-Adresse:", "Netmask": "Netzmaske:", "DefaultGateway": "Standardgateway:", - "Dns": "DNS Server {num}:", + "Dns": "DNS-Server {num}:", "Save": "@:dtuadmin.Save" }, "mqttadmin": { - "MqttSettings": "MQTT Einstellungen", - "MqttConfiguration": "MQTT Konfiguration", + "MqttSettings": "MQTT-Einstellungen", + "MqttConfiguration": "MQTT-Konfiguration", "EnableMqtt": "MQTT aktivieren", - "EnableHass": "Home Assistant MQTT Auto Discovery aktivieren", - "MqttBrokerParameter": "MQTT Broker Parameter", + "EnableHass": "Home Assistant MQTT-Auto-Discovery aktivieren", + "MqttBrokerParameter": "MQTT-Broker-Parameter", "Hostname": "Hostname:", - "HostnameHint": "Hostname oder IP Adresse", + "HostnameHint": "Hostname oder IP-Adresse", "Port": "Port:", "Username": "Benutzername:", "UsernameHint": "Benutzername, leer lassen für anonyme Verbindung", "Password": "Passwort:", "PasswordHint": "Passwort, leer lassen für anonyme Verbindung", - "BaseTopic": "Basis Topic:", - "BaseTopicHint": "Basis Topic, wird allen veröffentlichten Themen vorangestellt (z.B. inverter/)", + "BaseTopic": "Basis-Topic:", + "BaseTopicHint": "Basis-Topic, wird allen veröffentlichten Themen vorangestellt (z.B. inverter/)", "PublishInterval": "Veröffentlichungsintervall:", "Seconds": "Sekunden", "EnableRetain": "Retain Flag aktivieren", "EnableTls": "TLS aktivieren", "RootCa": "CA-Root-Zertifikat (Standard Letsencrypt):", - "LwtParameters": "LWT Parameter", - "LwtTopic": "LWT Topic:", - "LwtTopicHint": "LWT Topic, wird der Basis Topic angehängt", - "LwtOnline": "LWT Online Nachricht:", + "LwtParameters": "LWT-Parameter", + "LwtTopic": "LWT-Topic:", + "LwtTopicHint": "LWT-Topic, wird der Basis Topic angehängt", + "LwtOnline": "LWT-Online-Nachricht:", "LwtOnlineHint": "Nachricht, die im LWT-Topic veröffentlicht wird, wenn OpenDTU online ist", - "LwtOffline": "LWT Offline Nachricht:", + "LwtOffline": "LWT-Offline-Nachricht:", "LwtOfflineHint": "Nachricht, die im LWT-Topic veröffentlicht wird, wenn OpenDTU offline ist", - "HassParameters": "Home Assistant MQTT Auto Discovery Parameter", + "HassParameters": "Home Assistant MQTT-Auto-Discovery-Parameter", "HassPrefixTopic": "Präfix Topic:", "HassPrefixTopicHint": "The prefix for the discovery topic", "HassRetain": "Retain Flag aktivieren", @@ -418,7 +418,7 @@ "BackupConfig": "Sicherung der Konfigurationsdatei", "Backup": "Sichern", "Restore": "Wiederherstellen", - "NoFileSelected": "Keine Datei Ausgewählt", + "NoFileSelected": "Keine Datei ausgewählt", "RestoreHeader": "Wiederherstellen: Wiederherstellen der Konfigurationsdatei", "Back": "Zurück", "UploadSuccess": "Erfolgreich hochgeladen", @@ -433,7 +433,7 @@ }, "login": { "Login": "Anmeldung", - "SystemLogin": "System Anmeldung", + "SystemLogin": "Systemanmeldung", "Username": "Benutzername", "UsernameRequired": "Benutzername wird benötigt", "Password": "Passwort", @@ -441,48 +441,48 @@ "LoginButton": "Anmelden" }, "firmwareupgrade": { - "FirmwareUpgrade": "Firmware Update", + "FirmwareUpgrade": "Firmware-Aktualisierung", "Loading": "@:base.Loading", - "OtaError": "OTA Fehler", + "OtaError": "OTA-Fehler", "Back": "Zurück", "Retry": "Wiederholen", - "OtaStatus": "OTA Status", - "OtaSuccess": "OTA Erfolgreich. Das Gerät wurde automatisch neu gestartet und wird in wenigen Augenblicken wieder zur Verfügung stehen. Bitte nicht vergessen die Weboberfläche neu zu laden!", + "OtaStatus": "OTA-Status", + "OtaSuccess": "OTA erfolgreich. Das Gerät wurde automatisch neu gestartet und wird in wenigen Augenblicken wieder zur Verfügung stehen. Bitte nicht vergessen, die Weboberfläche neu zu laden!", "FirmwareUpload": "Firmware hochladen", - "UploadProgress": "Hochlade Fortschritt" + "UploadProgress": "Hochlade-Fortschritt" }, "about": { "AboutOpendtu": "Über OpenDTU", "ProjectOrigin": "Projekt Ursprung", - "ProjectOriginBody1": "Das Projekt wurde aus dieser Diskussion heraus gestartet. (Mikrocontroller.net)", + "ProjectOriginBody1": "Das Projekt wurde aus dieser Diskussion (mikrocontroller.net) heraus gestartet.", "ProjectOriginBody2": "Das Hoymiles-Protokoll wurde durch die freiwilligen Bemühungen vieler Teilnehmer entschlüsselt. OpenDTU wurde unter anderem auf der Grundlage dieser Arbeit entwickelt. Das Projekt ist unter einer Open-Source-Lizenz lizenziert (GNU General Public License version 2).", "ProjectOriginBody3": "Die Software wurde nach bestem Wissen und Gewissen entwickelt. Dennoch kann keine Haftung für eine Fehlfunktion oder einen Garantieverlust des Wechselrichters übernommen werden.", "ProjectOriginBody4": "OpenDTU ist frei verfügbar. Wenn Sie Geld für die Software bezahlt haben, wurden Sie wahrscheinlich abgezockt.", "NewsUpdates": "Neuigkeiten und Updates", "NewsUpdatesBody": "Neue Updates sind auf Github zu finden: https://github.com/tbnobody/OpenDTU", "ErrorReporting": "Fehlerberichte", - "ErrorReportingBody": "Bitte melden Sie Probleme über die von Github bereitgestellte Funktion.", + "ErrorReportingBody": "Bitte melden Sie Probleme über die Ticketverwaltung von Github.", "Discussion": "Diskussion", "DiscussionBody": "Diskutieren Sie mit uns auf Discord oder Github" }, "hints": { - "RadioProblem": "Es konnte keine Verbindung zu einem korrekten NRF24L01+ Funkmodul hergestellt werden. Bitte überprüfen Sie die Verdrahtung.", + "RadioProblem": "Es konnte keine Verbindung zu einem NRF24L01+ Funkmodul hergestellt werden. Bitte überprüfen Sie die Verdrahtung.", "TimeSync": "Die Uhr wurde noch nicht synchronisiert. Ohne eine korrekt eingestellte Uhr werden keine Anfragen an den Wechselrichter gesendet. Dies ist kurz nach dem Start normal. Nach einer längeren Laufzeit (>1 Minute) bedeutet es jedoch, dass der NTP-Server nicht erreichbar ist.", "TimeSyncLink": "Bitte überprüfen Sie Ihre Zeiteinstellungen.", "DefaultPassword": "Sie verwenden das Standardpasswort für die Weboberfläche und den Notfall Access Point. Dies ist potenziell unsicher.", "DefaultPasswordLink": "Bitte ändern Sie das Passwort." }, "deviceadmin": { - "DeviceManager": "Geräte-Manager", + "DeviceManager": "Hardware-Einstellungen", "PinAssignment": "Anschlusseinstellungen", "SelectedProfile": "Ausgewähltes Profil:", - "DefaultProfile": "(Standard Einstellungen)", + "DefaultProfile": "(Standardeinstellungen)", "ProfileHint": "Ihr Gerät reagiert möglicherweise nicht mehr, wenn Sie ein inkompatibles Profil wählen. In diesem Fall müssen Sie eine Löschung über das serielle Interface durchführen.", "Display": "Display", "PowerSafe": "Power Safe aktivieren:", - "PowerSafeHint": "Schaltet das Display aus wenn kein Wechselrichter produziert", + "PowerSafeHint": "Schaltet das Display aus, wenn kein Wechselrichter Strom erzeugt", "Screensaver": "Screensaver aktivieren:", - "ScreensaverHint": "Bewegt die Ausgabe bei jeder Aktualisierung um ein Einbrennen zu verhindern. (Nützlich v.a. für OLED Displays)", + "ScreensaverHint": "Bewegt die Ausgabe bei jeder Aktualisierung um ein Einbrennen zu verhindern (v. a. für OLED-Displays nützlich)", "ShowLogo": "Logo anzeigen:", "Contrast": "Kontrast ({contrast}):", "Save": "@:dtuadmin.Save" @@ -494,4 +494,4 @@ "ValueSelected": "Ausgewählt", "ValueActive": "Aktiv" } -} \ No newline at end of file +} From 7da782c4ef492a4bd6970325b9c58805d40a704f Mon Sep 17 00:00:00 2001 From: Thomas Basler Date: Sat, 18 Feb 2023 15:51:46 +0100 Subject: [PATCH 02/19] Hoymiles Lib: Added flags to inverter to enable/disable polling and commands to the inverter --- lib/Hoymiles/src/inverters/HM_Abstract.cpp | 28 +++++++++++++++++++ .../src/inverters/InverterAbstract.cpp | 20 +++++++++++++ lib/Hoymiles/src/inverters/InverterAbstract.h | 9 ++++++ 3 files changed, 57 insertions(+) diff --git a/lib/Hoymiles/src/inverters/HM_Abstract.cpp b/lib/Hoymiles/src/inverters/HM_Abstract.cpp index 63db5998..a07dec93 100644 --- a/lib/Hoymiles/src/inverters/HM_Abstract.cpp +++ b/lib/Hoymiles/src/inverters/HM_Abstract.cpp @@ -17,6 +17,10 @@ HM_Abstract::HM_Abstract(uint64_t serial) bool HM_Abstract::sendStatsRequest(HoymilesRadio* radio) { + if (!getEnablePolling()) { + return false; + } + struct tm timeinfo; if (!getLocalTime(&timeinfo, 5)) { return false; @@ -34,6 +38,10 @@ bool HM_Abstract::sendStatsRequest(HoymilesRadio* radio) bool HM_Abstract::sendAlarmLogRequest(HoymilesRadio* radio, bool force) { + if (!getEnablePolling()) { + return false; + } + struct tm timeinfo; if (!getLocalTime(&timeinfo, 5)) { return false; @@ -62,6 +70,10 @@ bool HM_Abstract::sendAlarmLogRequest(HoymilesRadio* radio, bool force) bool HM_Abstract::sendDevInfoRequest(HoymilesRadio* radio) { + if (!getEnablePolling()) { + return false; + } + struct tm timeinfo; if (!getLocalTime(&timeinfo, 5)) { return false; @@ -83,6 +95,10 @@ bool HM_Abstract::sendDevInfoRequest(HoymilesRadio* radio) bool HM_Abstract::sendSystemConfigParaRequest(HoymilesRadio* radio) { + if (!getEnablePolling()) { + return false; + } + struct tm timeinfo; if (!getLocalTime(&timeinfo, 5)) { return false; @@ -101,6 +117,10 @@ bool HM_Abstract::sendSystemConfigParaRequest(HoymilesRadio* radio) bool HM_Abstract::sendActivePowerControlRequest(HoymilesRadio* radio, float limit, PowerLimitControlType type) { + if (!getEnableCommands()) { + return false; + } + if (type == PowerLimitControlType::RelativNonPersistent || type == PowerLimitControlType::RelativPersistent) { limit = min(100, limit); } @@ -123,6 +143,10 @@ bool HM_Abstract::resendActivePowerControlRequest(HoymilesRadio* radio) bool HM_Abstract::sendPowerControlRequest(HoymilesRadio* radio, bool turnOn) { + if (!getEnableCommands()) { + return false; + } + if (turnOn) { _powerState = 1; } else { @@ -139,6 +163,10 @@ bool HM_Abstract::sendPowerControlRequest(HoymilesRadio* radio, bool turnOn) bool HM_Abstract::sendRestartControlRequest(HoymilesRadio* radio) { + if (!getEnableCommands()) { + return false; + } + _powerState = 2; PowerControlCommand* cmd = radio->enqueCommand(); diff --git a/lib/Hoymiles/src/inverters/InverterAbstract.cpp b/lib/Hoymiles/src/inverters/InverterAbstract.cpp index c9798473..8029995b 100644 --- a/lib/Hoymiles/src/inverters/InverterAbstract.cpp +++ b/lib/Hoymiles/src/inverters/InverterAbstract.cpp @@ -75,6 +75,26 @@ bool InverterAbstract::isReachable() return Statistics()->getRxFailureCount() <= MAX_ONLINE_FAILURE_COUNT; } +void InverterAbstract::setEnablePolling(bool enabled) +{ + _enablePolling = enabled; +} + +bool InverterAbstract::getEnablePolling() +{ + return _enablePolling; +} + +void InverterAbstract::setEnableCommands(bool enabled) +{ + _enableCommands = enabled; +} + +bool InverterAbstract::getEnableCommands() +{ + return _enableCommands; +} + AlarmLogParser* InverterAbstract::EventLog() { return _alarmLogParser.get(); diff --git a/lib/Hoymiles/src/inverters/InverterAbstract.h b/lib/Hoymiles/src/inverters/InverterAbstract.h index 6334c648..079bf7f4 100644 --- a/lib/Hoymiles/src/inverters/InverterAbstract.h +++ b/lib/Hoymiles/src/inverters/InverterAbstract.h @@ -44,6 +44,12 @@ public: bool isProducing(); bool isReachable(); + void setEnablePolling(bool enabled); + bool getEnablePolling(); + + void setEnableCommands(bool enabled); + bool getEnableCommands(); + void clearRxFragmentBuffer(); void addRxFragment(uint8_t fragment[], uint8_t len); uint8_t verifyAllFragments(CommandAbstract* cmd); @@ -73,6 +79,9 @@ private: uint8_t _rxFragmentLastPacketId = 0; uint8_t _rxFragmentRetransmitCnt = 0; + bool _enablePolling = true; + bool _enableCommands = true; + std::unique_ptr _alarmLogParser; std::unique_ptr _devInfoParser; std::unique_ptr _powerCommandParser; From 19a1c0aa543463a475ee50330f0e99627b5c03a7 Mon Sep 17 00:00:00 2001 From: Thomas Basler Date: Sat, 18 Feb 2023 16:40:24 +0100 Subject: [PATCH 03/19] Added config parameters to set longitude and latitude --- include/Configuration.h | 2 ++ include/defaults.h | 2 ++ src/Configuration.cpp | 4 ++++ src/WebApi_ntp.cpp | 6 +++++- webapp/src/components/InputElement.vue | 2 ++ webapp/src/locales/de.json | 3 +++ webapp/src/locales/en.json | 3 +++ webapp/src/locales/fr.json | 3 +++ webapp/src/types/NtpConfig.ts | 2 ++ webapp/src/views/NtpAdminView.vue | 10 ++++++++++ 10 files changed, 36 insertions(+), 1 deletion(-) diff --git a/include/Configuration.h b/include/Configuration.h index 15c037ae..449cf518 100644 --- a/include/Configuration.h +++ b/include/Configuration.h @@ -60,6 +60,8 @@ struct CONFIG_T { char Ntp_Server[NTP_MAX_SERVER_STRLEN + 1]; char Ntp_Timezone[NTP_MAX_TIMEZONE_STRLEN + 1]; char Ntp_TimezoneDescr[NTP_MAX_TIMEZONEDESCR_STRLEN + 1]; + double Ntp_Longitude; + double Ntp_Latitude; bool Mqtt_Enabled; uint Mqtt_Port; diff --git a/include/defaults.h b/include/defaults.h index 69ec960b..2a86d47a 100644 --- a/include/defaults.h +++ b/include/defaults.h @@ -23,6 +23,8 @@ #define NTP_SERVER "pool.ntp.org" #define NTP_TIMEZONE "CET-1CEST,M3.5.0,M10.5.0/3" #define NTP_TIMEZONEDESCR "Europe/Berlin" +#define NTP_LONGITUDE 10.4515f +#define NTP_LATITUDE 51.1657f #define MQTT_ENABLED false #define MQTT_HOST "" diff --git a/src/Configuration.cpp b/src/Configuration.cpp index 8ec7a9e8..eda2dc44 100644 --- a/src/Configuration.cpp +++ b/src/Configuration.cpp @@ -44,6 +44,8 @@ bool ConfigurationClass::write() ntp["server"] = config.Ntp_Server; ntp["timezone"] = config.Ntp_Timezone; ntp["timezone_descr"] = config.Ntp_TimezoneDescr; + ntp["latitude"] = config.Ntp_Latitude; + ntp["longitude"] = config.Ntp_Longitude; JsonObject mqtt = doc.createNestedObject("mqtt"); mqtt["enabled"] = config.Mqtt_Enabled; @@ -175,6 +177,8 @@ bool ConfigurationClass::read() strlcpy(config.Ntp_Server, ntp["server"] | NTP_SERVER, sizeof(config.Ntp_Server)); strlcpy(config.Ntp_Timezone, ntp["timezone"] | NTP_TIMEZONE, sizeof(config.Ntp_Timezone)); strlcpy(config.Ntp_TimezoneDescr, ntp["timezone_descr"] | NTP_TIMEZONEDESCR, sizeof(config.Ntp_TimezoneDescr)); + config.Ntp_Latitude = ntp["latitude"] | NTP_LATITUDE; + config.Ntp_Longitude = ntp["longitude"] | NTP_LONGITUDE; JsonObject mqtt = doc["mqtt"]; config.Mqtt_Enabled = mqtt["enabled"] | MQTT_ENABLED; diff --git a/src/WebApi_ntp.cpp b/src/WebApi_ntp.cpp index 53a92e87..12ea4eb6 100644 --- a/src/WebApi_ntp.cpp +++ b/src/WebApi_ntp.cpp @@ -68,6 +68,8 @@ void WebApiNtpClass::onNtpAdminGet(AsyncWebServerRequest* request) root[F("ntp_server")] = config.Ntp_Server; root[F("ntp_timezone")] = config.Ntp_Timezone; root[F("ntp_timezone_descr")] = config.Ntp_TimezoneDescr; + root[F("longitude")] = config.Ntp_Longitude; + root[F("latitude")] = config.Ntp_Latitude; response->setLength(); request->send(response); @@ -112,7 +114,7 @@ void WebApiNtpClass::onNtpAdminPost(AsyncWebServerRequest* request) return; } - if (!(root.containsKey("ntp_server") && root.containsKey("ntp_timezone"))) { + if (!(root.containsKey("ntp_server") && root.containsKey("ntp_timezone") && root.containsKey("longitude") && root.containsKey("latitude"))) { retMsg[F("message")] = F("Values are missing!"); retMsg[F("code")] = WebApiError::GenericValueMissing; response->setLength(); @@ -151,6 +153,8 @@ void WebApiNtpClass::onNtpAdminPost(AsyncWebServerRequest* request) strlcpy(config.Ntp_Server, root[F("ntp_server")].as().c_str(), sizeof(config.Ntp_Server)); strlcpy(config.Ntp_Timezone, root[F("ntp_timezone")].as().c_str(), sizeof(config.Ntp_Timezone)); strlcpy(config.Ntp_TimezoneDescr, root[F("ntp_timezone_descr")].as().c_str(), sizeof(config.Ntp_TimezoneDescr)); + config.Ntp_Latitude = root[F("latitude")].as(); + config.Ntp_Longitude = root[F("longitude")].as(); Configuration.write(); retMsg[F("type")] = F("success"); diff --git a/webapp/src/components/InputElement.vue b/webapp/src/components/InputElement.vue index c2ab2b43..eff8e9f6 100644 --- a/webapp/src/components/InputElement.vue +++ b/webapp/src/components/InputElement.vue @@ -27,6 +27,7 @@ :maxlength="maxlength" :min="min" :max="max" + :step="step" :disabled="disabled" :aria-describedby="descriptionId" /> @@ -69,6 +70,7 @@ export default defineComponent({ 'maxlength': String, 'min': String, 'max': String, + 'step': String, 'rows': String, 'disabled': Boolean, 'postfix': String, diff --git a/webapp/src/locales/de.json b/webapp/src/locales/de.json index 711ffedd..a6682bca 100644 --- a/webapp/src/locales/de.json +++ b/webapp/src/locales/de.json @@ -328,6 +328,9 @@ "TimeServerHint": "Der Standardwert ist in Ordnung, solange OpenDTU direkten Zugang zum Internet hat.", "Timezone": "Zeitzone:", "TimezoneConfig": "Zeitzonenkonfiguration:", + "LocationConfiguration": "Standortkonfiguration", + "Longitude": "Längengrad:", + "Latitude": "Breitengrad:", "Save": "@:dtuadmin.Save", "ManualTimeSynchronization": "Manuelle Zeitsynchronization", "CurrentOpenDtuTime": "Aktuelle OpenDTU Zeit:", diff --git a/webapp/src/locales/en.json b/webapp/src/locales/en.json index cd8bb553..2308b7c4 100644 --- a/webapp/src/locales/en.json +++ b/webapp/src/locales/en.json @@ -328,6 +328,9 @@ "TimeServerHint": "The default value is fine as long as OpenDTU has direct access to the internet.", "Timezone": "Timezone:", "TimezoneConfig": "Timezone Config:", + "LocationConfiguration": "Location Configuration", + "Longitude": "Longitude", + "Latitude": "Latitude", "Save": "@:dtuadmin.Save", "ManualTimeSynchronization": "Manual Time Synchronization", "CurrentOpenDtuTime": "Current OpenDTU Time:", diff --git a/webapp/src/locales/fr.json b/webapp/src/locales/fr.json index f9764a57..51c74b54 100644 --- a/webapp/src/locales/fr.json +++ b/webapp/src/locales/fr.json @@ -328,6 +328,9 @@ "TimeServerHint": "La valeur par défaut convient tant que OpenDTU a un accès direct à Internet.", "Timezone": "Fuseau horaire", "TimezoneConfig": "Configuration du fuseau horaire", + "LocationConfiguration": "Location Configuration", + "Longitude": "Longitude", + "Latitude": "Latitude", "Save": "@:dtuadmin.Save", "ManualTimeSynchronization": "Synchronisation manuelle de l'heure", "CurrentOpenDtuTime": "Heure actuelle de l'OpenDTU", diff --git a/webapp/src/types/NtpConfig.ts b/webapp/src/types/NtpConfig.ts index 38fd55c6..172ffa09 100644 --- a/webapp/src/types/NtpConfig.ts +++ b/webapp/src/types/NtpConfig.ts @@ -2,4 +2,6 @@ export interface NtpConfig { ntp_server: string; ntp_timezone: string; ntp_timezone_descr: string; + latitude: number; + longitude: number; } \ No newline at end of file diff --git a/webapp/src/views/NtpAdminView.vue b/webapp/src/views/NtpAdminView.vue index 174ec1e4..dc1ccd23 100644 --- a/webapp/src/views/NtpAdminView.vue +++ b/webapp/src/views/NtpAdminView.vue @@ -27,6 +27,16 @@ v-model="ntpConfigList.ntp_timezone" type="text" maxlength="32" disabled/> + + + + + + From b319c78dc1a0050e46ea0f9b66e5d75b93e95961 Mon Sep 17 00:00:00 2001 From: Thomas Basler Date: Sat, 18 Feb 2023 18:15:48 +0100 Subject: [PATCH 04/19] Added methods to calculate and show sunrise and sunset times --- include/SunPosition.h | 30 +++++++++++ include/Utils.h | 1 + platformio.ini | 1 + src/SunPosition.cpp | 88 ++++++++++++++++++++++++++++++++ src/Utils.cpp | 17 ++++++ src/WebApi_ntp.cpp | 11 ++++ src/main.cpp | 8 +++ webapp/src/locales/de.json | 7 ++- webapp/src/locales/en.json | 7 ++- webapp/src/locales/fr.json | 7 ++- webapp/src/types/NtpStatus.ts | 3 ++ webapp/src/views/NtpInfoView.vue | 19 +++++++ 12 files changed, 196 insertions(+), 3 deletions(-) create mode 100644 include/SunPosition.h create mode 100644 src/SunPosition.cpp diff --git a/include/SunPosition.h b/include/SunPosition.h new file mode 100644 index 00000000..49c5c71f --- /dev/null +++ b/include/SunPosition.h @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#pragma once + +#include + +#define SUNPOS_UPDATE_INTERVAL 60000l + +class SunPositionClass { +public: + SunPositionClass(); + void init(); + void loop(); + + bool isDayPeriod(); + bool sunsetTime(struct tm* info); + bool sunriseTime(struct tm* info); + +private: + void updateSunData(); + + SunSet _sun; + bool _isDayPeriod = true; + uint _sunriseMinutes = 0; + uint _sunsetMinutes = 0; + + uint32_t _lastUpdate = 0; + bool _isValidInfo = false; +}; + +extern SunPositionClass SunPosition; \ No newline at end of file diff --git a/include/Utils.h b/include/Utils.h index dbcea819..33887ff9 100644 --- a/include/Utils.h +++ b/include/Utils.h @@ -7,4 +7,5 @@ class Utils { public: static uint32_t getChipId(); static uint64_t generateDtuSerial(); + static int getTimezoneOffset(); }; diff --git a/platformio.ini b/platformio.ini index 7b328b8b..8686a378 100644 --- a/platformio.ini +++ b/platformio.ini @@ -27,6 +27,7 @@ lib_deps = https://github.com/bertmelis/espMqttClient.git#v1.3.3 nrf24/RF24 @ ^1.4.5 olikraus/U8g2 @ ^2.34.13 + buelowp/sunset @ ^1.1.3 extra_scripts = pre:auto_firmware_version.py diff --git a/src/SunPosition.cpp b/src/SunPosition.cpp new file mode 100644 index 00000000..1db5844e --- /dev/null +++ b/src/SunPosition.cpp @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023 Thomas Basler and others + */ +#include "SunPosition.h" +#include "Configuration.h" +#include "Utils.h" + +SunPositionClass SunPosition; + +SunPositionClass::SunPositionClass() +{ +} + +void SunPositionClass::init() +{ +} + +void SunPositionClass::loop() +{ + if (millis() - _lastUpdate > SUNPOS_UPDATE_INTERVAL) { + updateSunData(); + _lastUpdate = millis(); + } +} + +bool SunPositionClass::isDayPeriod() +{ + return _isDayPeriod; +} + +void SunPositionClass::updateSunData() +{ + CONFIG_T const& config = Configuration.get(); + int offset = Utils::getTimezoneOffset() / 3600; + _sun.setPosition(config.Ntp_Latitude, config.Ntp_Longitude, offset); + + struct tm timeinfo; + if (!getLocalTime(&timeinfo, 5)) { + _isDayPeriod = false; + _sunriseMinutes = 0; + _sunsetMinutes = 0; + _isValidInfo = false; + return; + } + + _sun.setCurrentDate(1900 + timeinfo.tm_year, timeinfo.tm_mon + 1, timeinfo.tm_mday); + _sunriseMinutes = (int)_sun.calcCustomSunrise(SunSet::SUNSET_NAUTICAL); + _sunsetMinutes = (int)_sun.calcCustomSunset(SunSet::SUNSET_NAUTICAL); + uint minutesPastMidnight = timeinfo.tm_hour * 60 + timeinfo.tm_min; + + _isDayPeriod = (minutesPastMidnight >= _sunriseMinutes) && (minutesPastMidnight < _sunsetMinutes); + _isValidInfo = true; +} + +bool SunPositionClass::sunsetTime(struct tm* info) +{ + // Get today's date + time_t aTime = time(NULL); + + // Set the time to midnight + struct tm* tm = localtime(&aTime); + tm->tm_sec = 0; + tm->tm_min = _sunsetMinutes; + tm->tm_hour = 0; + tm->tm_isdst = -1; + time_t midnight = mktime(tm); + + localtime_r(&midnight, info); + return _isValidInfo; +} + +bool SunPositionClass::sunriseTime(struct tm* info) +{ + // Get today's date + time_t aTime = time(NULL); + + // Set the time to midnight + struct tm* tm = localtime(&aTime); + tm->tm_sec = 0; + tm->tm_min = _sunriseMinutes; + tm->tm_hour = 0; + tm->tm_isdst = -1; + time_t midnight = mktime(tm); + + localtime_r(&midnight, info); + return _isValidInfo; +} \ No newline at end of file diff --git a/src/Utils.cpp b/src/Utils.cpp index f1975aff..db8363ad 100644 --- a/src/Utils.cpp +++ b/src/Utils.cpp @@ -35,4 +35,21 @@ uint64_t Utils::generateDtuSerial() } return dtuId; +} + +int Utils::getTimezoneOffset() +{ + // see: https://stackoverflow.com/questions/13804095/get-the-time-zone-gmt-offset-in-c/44063597#44063597 + + time_t gmt, rawtime = time(NULL); + struct tm* ptm; + + struct tm gbuf; + ptm = gmtime_r(&rawtime, &gbuf); + + // Request that mktime() looksup dst in timezone database + ptm->tm_isdst = -1; + gmt = mktime(ptm); + + return static_cast(difftime(rawtime, gmt)); } \ No newline at end of file diff --git a/src/WebApi_ntp.cpp b/src/WebApi_ntp.cpp index 12ea4eb6..836247a0 100644 --- a/src/WebApi_ntp.cpp +++ b/src/WebApi_ntp.cpp @@ -5,6 +5,7 @@ #include "WebApi_ntp.h" #include "Configuration.h" #include "NtpSettings.h" +#include "SunPosition.h" #include "WebApi.h" #include "WebApi_errors.h" #include "helper.h" @@ -51,6 +52,16 @@ void WebApiNtpClass::onNtpStatus(AsyncWebServerRequest* request) strftime(timeStringBuff, sizeof(timeStringBuff), "%A, %B %d %Y %H:%M:%S", &timeinfo); root[F("ntp_localtime")] = timeStringBuff; + SunPosition.sunriseTime(&timeinfo); + strftime(timeStringBuff, sizeof(timeStringBuff), "%A, %B %d %Y %H:%M:%S", &timeinfo); + root[F("sun_risetime")] = timeStringBuff; + + SunPosition.sunsetTime(&timeinfo); + strftime(timeStringBuff, sizeof(timeStringBuff), "%A, %B %d %Y %H:%M:%S", &timeinfo); + root[F("sun_settime")] = timeStringBuff; + + root[F("sun_isDayPeriod")] = SunPosition.isDayPeriod(); + response->setLength(); request->send(response); } diff --git a/src/main.cpp b/src/main.cpp index 273a7bb6..6191e4b8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -12,6 +12,7 @@ #include "NetworkSettings.h" #include "NtpSettings.h" #include "PinMapping.h" +#include "SunPosition.h" #include "Utils.h" #include "WebApi.h" #include "defaults.h" @@ -80,6 +81,11 @@ void setup() NtpSettings.init(); MessageOutput.println(F("done")); + // Initialize SunPosition + MessageOutput.print(F("Initialize SunPosition... ")); + SunPosition.init(); + MessageOutput.println(F("done")); + // Initialize MqTT MessageOutput.print(F("Initialize MqTT... ")); MqttSettings.init(); @@ -178,6 +184,8 @@ void loop() yield(); Display.loop(); yield(); + SunPosition.loop(); + yield(); MessageOutput.loop(); yield(); } \ No newline at end of file diff --git a/webapp/src/locales/de.json b/webapp/src/locales/de.json index a6682bca..b7bfa67b 100644 --- a/webapp/src/locales/de.json +++ b/webapp/src/locales/de.json @@ -228,7 +228,12 @@ "Status": "Status", "Synced": "synchronisiert", "NotSynced": "nicht synchronisiert", - "LocalTime": "Lokale Uhrzeit" + "LocalTime": "Lokale Uhrzeit", + "Sunrise": "Nautische Morgendämmerung", + "Sunset": "Nautische Abenddämmerung", + "Mode": "Modus", + "Day": "Tag", + "Night": "Nacht" }, "mqttinfo": { "MqttInformation": "MQTT Informationen", diff --git a/webapp/src/locales/en.json b/webapp/src/locales/en.json index 2308b7c4..a11b3840 100644 --- a/webapp/src/locales/en.json +++ b/webapp/src/locales/en.json @@ -228,7 +228,12 @@ "Status": "Status", "Synced": "synced", "NotSynced": "not synced", - "LocalTime": "Local Time" + "LocalTime": "Local Time", + "Sunrise": "Nautical Sunrise", + "Sunset": "Nautical Sunset", + "Mode": "Mode", + "Day": "Day", + "Night": "Night" }, "mqttinfo": { "MqttInformation": "MQTT Information", diff --git a/webapp/src/locales/fr.json b/webapp/src/locales/fr.json index 51c74b54..f026fe5f 100644 --- a/webapp/src/locales/fr.json +++ b/webapp/src/locales/fr.json @@ -228,7 +228,12 @@ "Status": "Statut", "Synced": "synchronisée", "NotSynced": "pas synchronisée", - "LocalTime": "Heure locale" + "LocalTime": "Heure locale", + "Sunrise": "Nautical Sunrise", + "Sunset": "Nautical Sunset", + "Mode": "Mode", + "Day": "Day", + "Night": "Night" }, "mqttinfo": { "MqttInformation": "MQTT Information", diff --git a/webapp/src/types/NtpStatus.ts b/webapp/src/types/NtpStatus.ts index 29b2d4a2..55975751 100644 --- a/webapp/src/types/NtpStatus.ts +++ b/webapp/src/types/NtpStatus.ts @@ -4,4 +4,7 @@ export interface NtpStatus { ntp_timezone_descr: string ntp_status: boolean; ntp_localtime: string; + sun_risetime: string; + sun_settime: string; + sun_isDayPeriod: boolean; } \ No newline at end of file diff --git a/webapp/src/views/NtpInfoView.vue b/webapp/src/views/NtpInfoView.vue index 35d9e168..71cc8f20 100644 --- a/webapp/src/views/NtpInfoView.vue +++ b/webapp/src/views/NtpInfoView.vue @@ -39,6 +39,25 @@ {{ $t('ntpinfo.LocalTime') }} {{ ntpDataList.ntp_localtime }} + + + {{ $t('ntpinfo.Sunrise') }} + {{ ntpDataList.sun_risetime }} + + + {{ $t('ntpinfo.Sunset') }} + {{ ntpDataList.sun_settime }} + + + {{ $t('ntpinfo.Mode') }} + + {{ $t('ntpinfo.Day') }} + {{ $t('ntpinfo.Night') }} + + From cd99ab8e4231cbe1693aeafb4f64c28ef76827b2 Mon Sep 17 00:00:00 2001 From: Thomas Basler Date: Sat, 18 Feb 2023 19:44:16 +0100 Subject: [PATCH 05/19] Added settings to pause polling/sending commands in general and at night --- include/Configuration.h | 4 ++ include/InverterSettings.h | 15 +++++ src/Configuration.cpp | 9 +++ src/InverterSettings.cpp | 82 ++++++++++++++++++++++++++ src/WebApi_inverter.cpp | 11 ++++ src/main.cpp | 45 +------------- webapp/src/locales/de.json | 5 ++ webapp/src/locales/en.json | 5 ++ webapp/src/locales/fr.json | 5 ++ webapp/src/views/InverterAdminView.vue | 21 +++++++ 10 files changed, 160 insertions(+), 42 deletions(-) create mode 100644 include/InverterSettings.h create mode 100644 src/InverterSettings.cpp diff --git a/include/Configuration.h b/include/Configuration.h index 449cf518..8d88bbd9 100644 --- a/include/Configuration.h +++ b/include/Configuration.h @@ -40,6 +40,10 @@ struct CHANNEL_CONFIG_T { struct INVERTER_CONFIG_T { uint64_t Serial; char Name[INV_MAX_NAME_STRLEN + 1]; + bool Poll_Enable; + bool Poll_Enable_Night; + bool Command_Enable; + bool Command_Enable_Night; CHANNEL_CONFIG_T channel[INV_MAX_CHAN_COUNT]; }; diff --git a/include/InverterSettings.h b/include/InverterSettings.h new file mode 100644 index 00000000..188025b1 --- /dev/null +++ b/include/InverterSettings.h @@ -0,0 +1,15 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +#pragma once + +#include + +class InverterSettingsClass { +public: + void init(); + void loop(); + +private: + uint32_t _lastUpdate = 0; +}; + +extern InverterSettingsClass InverterSettings; \ No newline at end of file diff --git a/src/Configuration.cpp b/src/Configuration.cpp index eda2dc44..43e75e82 100644 --- a/src/Configuration.cpp +++ b/src/Configuration.cpp @@ -96,6 +96,10 @@ bool ConfigurationClass::write() JsonObject inv = inverters.createNestedObject(); inv["serial"] = config.Inverter[i].Serial; inv["name"] = config.Inverter[i].Name; + inv["poll_enable"] = config.Inverter[i].Poll_Enable; + inv["poll_enable_night"] = config.Inverter[i].Poll_Enable_Night; + inv["command_enable"] = config.Inverter[i].Command_Enable; + inv["command_enable_night"] = config.Inverter[i].Command_Enable_Night; JsonArray channel = inv.createNestedArray("channel"); for (uint8_t c = 0; c < INV_MAX_CHAN_COUNT; c++) { @@ -230,6 +234,11 @@ bool ConfigurationClass::read() config.Inverter[i].Serial = inv["serial"] | 0ULL; strlcpy(config.Inverter[i].Name, inv["name"] | "", sizeof(config.Inverter[i].Name)); + config.Inverter[i].Poll_Enable = inv["poll_enable"] | true; + config.Inverter[i].Poll_Enable_Night = inv["poll_enable_night"] | true; + config.Inverter[i].Command_Enable = inv["command_enable"] | true; + config.Inverter[i].Command_Enable_Night = inv["command_enable_night"] | true; + JsonArray channel = inv["channel"]; for (uint8_t c = 0; c < INV_MAX_CHAN_COUNT; c++) { config.Inverter[i].channel[c].MaxChannelPower = channel[c]["max_power"] | 0; diff --git a/src/InverterSettings.cpp b/src/InverterSettings.cpp new file mode 100644 index 00000000..ebb354bb --- /dev/null +++ b/src/InverterSettings.cpp @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2023 Thomas Basler and others + */ +#include "InverterSettings.h" +#include "Configuration.h" +#include "MessageOutput.h" +#include "PinMapping.h" +#include "SunPosition.h" +#include + +InverterSettingsClass InverterSettings; + +void InverterSettingsClass::init() +{ + const CONFIG_T& config = Configuration.get(); + const PinMapping_t& pin = PinMapping.get(); + + // Initialize inverter communication + MessageOutput.print(F("Initialize Hoymiles interface... ")); + if (PinMapping.isValidNrf24Config()) { + SPIClass* spiClass = new SPIClass(HSPI); + spiClass->begin(pin.nrf24_clk, pin.nrf24_miso, pin.nrf24_mosi, pin.nrf24_cs); + Hoymiles.setMessageOutput(&MessageOutput); + Hoymiles.init(spiClass, pin.nrf24_en, pin.nrf24_irq); + + MessageOutput.println(F(" Setting radio PA level... ")); + Hoymiles.getRadio()->setPALevel((rf24_pa_dbm_e)config.Dtu_PaLevel); + + MessageOutput.println(F(" Setting DTU serial... ")); + Hoymiles.getRadio()->setDtuSerial(config.Dtu_Serial); + + MessageOutput.println(F(" Setting poll interval... ")); + Hoymiles.setPollInterval(config.Dtu_PollInterval); + + for (uint8_t i = 0; i < INV_MAX_COUNT; i++) { + if (config.Inverter[i].Serial > 0) { + MessageOutput.print(F(" Adding inverter: ")); + MessageOutput.print(config.Inverter[i].Serial, HEX); + MessageOutput.print(F(" - ")); + MessageOutput.print(config.Inverter[i].Name); + auto inv = Hoymiles.addInverter( + config.Inverter[i].Name, + config.Inverter[i].Serial); + + if (inv != nullptr) { + for (uint8_t c = 0; c < INV_MAX_CHAN_COUNT; c++) { + inv->Statistics()->setStringMaxPower(c, config.Inverter[i].channel[c].MaxChannelPower); + inv->Statistics()->setChannelFieldOffset(TYPE_DC, static_cast(c), FLD_YT, config.Inverter[i].channel[c].YieldTotalOffset); + } + } + MessageOutput.println(F(" done")); + } + } + MessageOutput.println(F("done")); + } else { + MessageOutput.println(F("Invalid pin config")); + } +} + +void InverterSettingsClass::loop() +{ + if (millis() - _lastUpdate > SUNPOS_UPDATE_INTERVAL) { + const CONFIG_T& config = Configuration.get(); + + for (uint8_t i = 0; i < INV_MAX_COUNT; i++) { + auto const& inv_cfg = config.Inverter[i]; + if (inv_cfg.Serial == 0) { + continue; + } + auto inv = Hoymiles.getInverterBySerial(inv_cfg.Serial); + if (inv == nullptr) { + continue; + } + + inv->setEnablePolling(inv_cfg.Poll_Enable && (SunPosition.isDayPeriod() || inv_cfg.Poll_Enable_Night)); + inv->setEnableCommands(inv_cfg.Command_Enable && (SunPosition.isDayPeriod() || inv_cfg.Command_Enable_Night)); + } + } + + Hoymiles.loop(); +} \ No newline at end of file diff --git a/src/WebApi_inverter.cpp b/src/WebApi_inverter.cpp index 77a9c887..f133167d 100644 --- a/src/WebApi_inverter.cpp +++ b/src/WebApi_inverter.cpp @@ -51,6 +51,10 @@ void WebApiInverterClass::onInverterList(AsyncWebServerRequest* request) ((uint32_t)((config.Inverter[i].Serial >> 32) & 0xFFFFFFFF)), ((uint32_t)(config.Inverter[i].Serial & 0xFFFFFFFF))); obj[F("serial")] = buffer; + obj[F("poll_enable")] = config.Inverter[i].Poll_Enable; + obj[F("poll_enable_night")] = config.Inverter[i].Poll_Enable_Night; + obj[F("command_enable")] = config.Inverter[i].Command_Enable; + obj[F("command_enable_night")] = config.Inverter[i].Command_Enable_Night; auto inv = Hoymiles.getInverterBySerial(config.Inverter[i].Serial); uint8_t max_channels; @@ -270,6 +274,11 @@ void WebApiInverterClass::onInverterEdit(AsyncWebServerRequest* request) inverter.channel[arrayCount].MaxChannelPower = channel[F("max_power")].as(); inverter.channel[arrayCount].YieldTotalOffset = channel[F("yield_total_offset")].as(); strncpy(inverter.channel[arrayCount].Name, channel[F("name")] | "", sizeof(inverter.channel[arrayCount].Name)); + inverter.Poll_Enable = root[F("poll_enable")] | true; + inverter.Poll_Enable_Night = root[F("poll_enable_night")] | true; + inverter.Command_Enable = root[F("command_enable")] | true; + inverter.Command_Enable_Night = root[F("command_enable_night")] | true; + arrayCount++; } @@ -297,6 +306,8 @@ void WebApiInverterClass::onInverterEdit(AsyncWebServerRequest* request) } if (inv != nullptr) { + inv->setEnablePolling(inverter.Poll_Enable); + inv->setEnableCommands(inverter.Command_Enable); for (uint8_t c = 0; c < INV_MAX_CHAN_COUNT; c++) { inv->Statistics()->setStringMaxPower(c, inverter.channel[c].MaxChannelPower); inv->Statistics()->setChannelFieldOffset(TYPE_DC, static_cast(c), FLD_YT, inverter.channel[c].YieldTotalOffset); diff --git a/src/main.cpp b/src/main.cpp index 6191e4b8..3cdefa33 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,6 +4,7 @@ */ #include "Configuration.h" #include "Display_Graphic.h" +#include "InverterSettings.h" #include "MessageOutput.h" #include "MqttHandleDtu.h" #include "MqttHandleHass.h" @@ -17,7 +18,6 @@ #include "WebApi.h" #include "defaults.h" #include -#include #include void setup() @@ -126,53 +126,14 @@ void setup() } MessageOutput.println(F("done")); - // Initialize inverter communication - MessageOutput.print(F("Initialize Hoymiles interface... ")); - if (PinMapping.isValidNrf24Config()) { - SPIClass* spiClass = new SPIClass(HSPI); - spiClass->begin(pin.nrf24_clk, pin.nrf24_miso, pin.nrf24_mosi, pin.nrf24_cs); - Hoymiles.setMessageOutput(&MessageOutput); - Hoymiles.init(spiClass, pin.nrf24_en, pin.nrf24_irq); - - MessageOutput.println(F(" Setting radio PA level... ")); - Hoymiles.getRadio()->setPALevel((rf24_pa_dbm_e)config.Dtu_PaLevel); - - MessageOutput.println(F(" Setting DTU serial... ")); - Hoymiles.getRadio()->setDtuSerial(config.Dtu_Serial); - - MessageOutput.println(F(" Setting poll interval... ")); - Hoymiles.setPollInterval(config.Dtu_PollInterval); - - for (uint8_t i = 0; i < INV_MAX_COUNT; i++) { - if (config.Inverter[i].Serial > 0) { - MessageOutput.print(F(" Adding inverter: ")); - MessageOutput.print(config.Inverter[i].Serial, HEX); - MessageOutput.print(F(" - ")); - MessageOutput.print(config.Inverter[i].Name); - auto inv = Hoymiles.addInverter( - config.Inverter[i].Name, - config.Inverter[i].Serial); - - if (inv != nullptr) { - for (uint8_t c = 0; c < INV_MAX_CHAN_COUNT; c++) { - inv->Statistics()->setStringMaxPower(c, config.Inverter[i].channel[c].MaxChannelPower); - inv->Statistics()->setChannelFieldOffset(TYPE_DC, static_cast(c), FLD_YT, config.Inverter[i].channel[c].YieldTotalOffset); - } - } - MessageOutput.println(F(" done")); - } - } - MessageOutput.println(F("done")); - } else { - MessageOutput.println(F("Invalid pin config")); - } + InverterSettings.init(); } void loop() { NetworkSettings.loop(); yield(); - Hoymiles.loop(); + InverterSettings.loop(); yield(); MqttHandleDtu.loop(); yield(); diff --git a/webapp/src/locales/de.json b/webapp/src/locales/de.json index b7bfa67b..a30620d9 100644 --- a/webapp/src/locales/de.json +++ b/webapp/src/locales/de.json @@ -408,6 +408,11 @@ "InverterSerial": "Wechselrichter Seriennummer:", "InverterName": "Wechselrichter Name:", "InverterNameHint": "Hier kann ein eigener Namen für den Wechselrichter angeben werden.", + "InverterStatus": "Empfangen / senden", + "PollEnable": "Daten abrufen", + "PollEnableNight": "Daten auch nachts abrufen", + "CommandEnable": "Befehle senden", + "CommandEnableNight": "Befehle auch nachts senden", "StringName": "Name String {num}:", "StringNameHint": "Hier kann ein eigener Name für den entsprechenden Port des Wechselrichters angegeben werden.", "StringMaxPower": "Max. Leistung String {num}:", diff --git a/webapp/src/locales/en.json b/webapp/src/locales/en.json index a11b3840..cfb659ca 100644 --- a/webapp/src/locales/en.json +++ b/webapp/src/locales/en.json @@ -408,6 +408,11 @@ "InverterSerial": "Inverter Serial:", "InverterName": "Inverter Name:", "InverterNameHint": "Here you can specify a custom name for your inverter.", + "InverterStatus": "Receive / Send", + "PollEnable": "Poll inverter data", + "PollEnableNight": "Poll inverter data at night", + "CommandEnable": "Send commands", + "CommandEnableNight": "Send commands at night", "StringName": "Name string {num}:", "StringNameHint": "Here you can specify a custom name for the respective port of your inverter.", "StringMaxPower": "Max power string {num}:", diff --git a/webapp/src/locales/fr.json b/webapp/src/locales/fr.json index f026fe5f..571a7859 100644 --- a/webapp/src/locales/fr.json +++ b/webapp/src/locales/fr.json @@ -408,6 +408,11 @@ "InverterSerial": "Numéro de série de l'onduleur", "InverterName": "Nom de l'onduleur :", "InverterNameHint": "Ici, vous pouvez spécifier un nom personnalisé pour votre onduleur.", + "InverterStatus": "Receive / Send", + "PollEnable": "Poll inverter data", + "PollEnableNight": "Poll inverter data at night", + "CommandEnable": "Send commands", + "CommandEnableNight": "Send commands at night", "StringName": "Nom de la ligne {num}:", "StringNameHint": "Ici, vous pouvez spécifier un nom personnalisé pour le port respectif de votre onduleur.", "StringMaxPower": "Puissance maximale de la ligne {num}:", diff --git a/webapp/src/views/InverterAdminView.vue b/webapp/src/views/InverterAdminView.vue index b30f0834..b457d91f 100644 --- a/webapp/src/views/InverterAdminView.vue +++ b/webapp/src/views/InverterAdminView.vue @@ -74,6 +74,21 @@ + + + + + + +
@@ -168,6 +183,7 @@ import BasePage from '@/components/BasePage.vue'; import BootstrapAlert from "@/components/BootstrapAlert.vue"; import CardElement from '@/components/CardElement.vue'; +import InputElement from '@/components/InputElement.vue'; import { authHeader, handleResponse } from '@/utils/authentication'; import * as bootstrap from 'bootstrap'; import { @@ -188,6 +204,10 @@ declare interface Inverter { serial: number; name: string; type: string; + poll_enable: boolean; + poll_enable_night: boolean; + command_enable: boolean; + command_enable_night: boolean; channel: Array; } @@ -206,6 +226,7 @@ export default defineComponent({ BIconInfoCircle, BIconPencil, BIconTrash, + InputElement, }, data() { return { From 4c14417ea867cedcba506cec487c3097544d5f35 Mon Sep 17 00:00:00 2001 From: Thomas Basler Date: Sat, 18 Feb 2023 20:29:18 +0100 Subject: [PATCH 06/19] webapp: Add column inverter settings to show inverter send/receive status --- webapp/src/locales/de.json | 1 + webapp/src/locales/en.json | 1 + webapp/src/locales/fr.json | 1 + webapp/src/views/InverterAdminView.vue | 22 +++++++++++++++++++--- 4 files changed, 22 insertions(+), 3 deletions(-) diff --git a/webapp/src/locales/de.json b/webapp/src/locales/de.json index a30620d9..d1a78e97 100644 --- a/webapp/src/locales/de.json +++ b/webapp/src/locales/de.json @@ -401,6 +401,7 @@ "Add": "Hinzufügen", "AddHint": "Hinweis: Sie können zusätzliche Parameter einstellen, nachdem Sie den Wechselrichter erstellt haben. Verwenden Sie dazu das Stiftsymbol in der Wechselrichterliste.", "InverterList": "Wechselrichterliste", + "Status": "Status", "Type": "Typ", "Action": "Aktion", "DeleteInverter": "Wechselrichter löschen", diff --git a/webapp/src/locales/en.json b/webapp/src/locales/en.json index cfb659ca..cf6824bd 100644 --- a/webapp/src/locales/en.json +++ b/webapp/src/locales/en.json @@ -401,6 +401,7 @@ "Add": "Add", "AddHint": "Hint: You can set additional parameters after you have created the inverter. Use the pen icon in the inverter list.", "InverterList": "Inverter List", + "Status": "Status", "Type": "Type", "Action": "Action", "DeleteInverter": "Delete inverter", diff --git a/webapp/src/locales/fr.json b/webapp/src/locales/fr.json index 571a7859..66f5e753 100644 --- a/webapp/src/locales/fr.json +++ b/webapp/src/locales/fr.json @@ -401,6 +401,7 @@ "Add": "Ajouter", "AddHint": " Astuce : Vous pouvez définir des paramètres supplémentaires après avoir créé l'onduleur. Utilisez l'icône du stylo dans la liste des onduleurs.", "InverterList": "Liste des onduleurs", + "Status": "Status", "Type": "Type", "Action": "Action", "DeleteInverter": "Supprimer l'onduleur", diff --git a/webapp/src/views/InverterAdminView.vue b/webapp/src/views/InverterAdminView.vue index b457d91f..2d63663c 100644 --- a/webapp/src/views/InverterAdminView.vue +++ b/webapp/src/views/InverterAdminView.vue @@ -28,7 +28,8 @@ - + + @@ -36,6 +37,17 @@ + @@ -189,7 +201,9 @@ import * as bootstrap from 'bootstrap'; import { BIconInfoCircle, BIconPencil, - BIconTrash + BIconTrash, + BIconArrowDown, + BIconArrowUp, } from 'bootstrap-icons-vue'; import { defineComponent } from 'vue'; @@ -223,10 +237,12 @@ export default defineComponent({ BasePage, BootstrapAlert, CardElement, + InputElement, BIconInfoCircle, BIconPencil, BIconTrash, - InputElement, + BIconArrowDown, + BIconArrowUp, }, data() { return { From e5e236510ef56cc71a92e6bd3f724488d454150d Mon Sep 17 00:00:00 2001 From: Thomas Basler Date: Sat, 18 Feb 2023 20:47:09 +0100 Subject: [PATCH 07/19] webapp: Add additional hint that no data is received if no sun is shining --- webapp/src/locales/de.json | 1 + webapp/src/locales/en.json | 3 ++- webapp/src/locales/fr.json | 1 + webapp/src/views/InverterAdminView.vue | 1 + 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/webapp/src/locales/de.json b/webapp/src/locales/de.json index d1a78e97..2b2e3315 100644 --- a/webapp/src/locales/de.json +++ b/webapp/src/locales/de.json @@ -402,6 +402,7 @@ "AddHint": "Hinweis: Sie können zusätzliche Parameter einstellen, nachdem Sie den Wechselrichter erstellt haben. Verwenden Sie dazu das Stiftsymbol in der Wechselrichterliste.", "InverterList": "Wechselrichterliste", "Status": "Status", + "StatusHint": "Hinweis: Der Wechselrichter wird über seinen DC-Eingang mit Strom versorgt. Wenn keine Sonne scheint, ist der Wechselrichter aus. Es können trotzdem Anfragen gesendet werden.", "Type": "Typ", "Action": "Aktion", "DeleteInverter": "Wechselrichter löschen", diff --git a/webapp/src/locales/en.json b/webapp/src/locales/en.json index cf6824bd..4fbb9e87 100644 --- a/webapp/src/locales/en.json +++ b/webapp/src/locales/en.json @@ -402,6 +402,7 @@ "AddHint": "Hint: You can set additional parameters after you have created the inverter. Use the pen icon in the inverter list.", "InverterList": "Inverter List", "Status": "Status", + "StatusHint": "Hint: The inverter is power by it's DC input. If there is no sun, the inverter is off. Requests can still be sent.", "Type": "Type", "Action": "Action", "DeleteInverter": "Delete inverter", @@ -419,7 +420,7 @@ "StringMaxPower": "Max power string {num}:", "StringMaxPowerHint": "Enter the max power of the connected solar panels.", "StringYtOffset": "Yield total offset string {num}:", - "StringYtOffsetHint": "This offset is applied the read yield total value from the inverter. This can be used to set the yield total of the inverter to zero if a used inverter is used.", + "StringYtOffsetHint": "This offset is applied the read yield total value from the inverter. This can be used to set the yield total of the inverter to zero if a used inverter is used. But you can still try polling data.", "InverterHint": "*) Enter the Wp of the channel to calculate irradiation.", "Cancel": "@:maintenancereboot.Cancel", "Save": "@:dtuadmin.Save", diff --git a/webapp/src/locales/fr.json b/webapp/src/locales/fr.json index 66f5e753..3ffdddd5 100644 --- a/webapp/src/locales/fr.json +++ b/webapp/src/locales/fr.json @@ -402,6 +402,7 @@ "AddHint": " Astuce : Vous pouvez définir des paramètres supplémentaires après avoir créé l'onduleur. Utilisez l'icône du stylo dans la liste des onduleurs.", "InverterList": "Liste des onduleurs", "Status": "Status", + "StatusHint": "Astuce : The inverter is power by it's DC input. If there is no sun, the inverter is off. Requests can still be sent.", "Type": "Type", "Action": "Action", "DeleteInverter": "Supprimer l'onduleur", diff --git a/webapp/src/views/InverterAdminView.vue b/webapp/src/views/InverterAdminView.vue index 2d63663c..a69f30cb 100644 --- a/webapp/src/views/InverterAdminView.vue +++ b/webapp/src/views/InverterAdminView.vue @@ -100,6 +100,7 @@ + From f6dedf7adbd46174338551677a1fd436c743b1a3 Mon Sep 17 00:00:00 2001 From: Thomas Basler Date: Sat, 18 Feb 2023 22:04:18 +0100 Subject: [PATCH 08/19] webapp: Add missing translations --- webapp/src/locales/de.json | 2 ++ webapp/src/locales/en.json | 2 ++ webapp/src/locales/fr.json | 2 ++ webapp/src/views/InverterAdminView.vue | 4 ++-- 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/webapp/src/locales/de.json b/webapp/src/locales/de.json index 2b2e3315..6a670c1c 100644 --- a/webapp/src/locales/de.json +++ b/webapp/src/locales/de.json @@ -402,6 +402,8 @@ "AddHint": "Hinweis: Sie können zusätzliche Parameter einstellen, nachdem Sie den Wechselrichter erstellt haben. Verwenden Sie dazu das Stiftsymbol in der Wechselrichterliste.", "InverterList": "Wechselrichterliste", "Status": "Status", + "Send": "Senden", + "Receive": "Empfangen", "StatusHint": "Hinweis: Der Wechselrichter wird über seinen DC-Eingang mit Strom versorgt. Wenn keine Sonne scheint, ist der Wechselrichter aus. Es können trotzdem Anfragen gesendet werden.", "Type": "Typ", "Action": "Aktion", diff --git a/webapp/src/locales/en.json b/webapp/src/locales/en.json index 4fbb9e87..0cecd1a6 100644 --- a/webapp/src/locales/en.json +++ b/webapp/src/locales/en.json @@ -402,6 +402,8 @@ "AddHint": "Hint: You can set additional parameters after you have created the inverter. Use the pen icon in the inverter list.", "InverterList": "Inverter List", "Status": "Status", + "Send": "Send", + "Receive": "Receive", "StatusHint": "Hint: The inverter is power by it's DC input. If there is no sun, the inverter is off. Requests can still be sent.", "Type": "Type", "Action": "Action", diff --git a/webapp/src/locales/fr.json b/webapp/src/locales/fr.json index 3ffdddd5..4837f3e8 100644 --- a/webapp/src/locales/fr.json +++ b/webapp/src/locales/fr.json @@ -402,6 +402,8 @@ "AddHint": " Astuce : Vous pouvez définir des paramètres supplémentaires après avoir créé l'onduleur. Utilisez l'icône du stylo dans la liste des onduleurs.", "InverterList": "Liste des onduleurs", "Status": "Status", + "Send": "Send", + "Receive": "Receive", "StatusHint": "Astuce : The inverter is power by it's DC input. If there is no sun, the inverter is off. Requests can still be sent.", "Type": "Type", "Action": "Action", diff --git a/webapp/src/views/InverterAdminView.vue b/webapp/src/views/InverterAdminView.vue index a69f30cb..558e5ddd 100644 --- a/webapp/src/views/InverterAdminView.vue +++ b/webapp/src/views/InverterAdminView.vue @@ -38,12 +38,12 @@ - - @@ -35,12 +33,14 @@ \ No newline at end of file diff --git a/webapp/src/components/WifiApInfo.vue b/webapp/src/components/WifiApInfo.vue index f00858ca..e2647dda 100644 --- a/webapp/src/components/WifiApInfo.vue +++ b/webapp/src/components/WifiApInfo.vue @@ -5,12 +5,8 @@ - @@ -29,12 +25,14 @@
{{ $t('inverteradmin.Serial') }}{{ $t('inverteradmin.Status') }}{{ $t('inverteradmin.Serial') }} {{ $t('inverteradmin.Name') }} {{ $t('inverteradmin.Type') }} {{ $t('inverteradmin.Action') }}
+ + + + {{ inverter.serial }} {{ inverter.name }} {{ inverter.type }}
- - From 42b60060a1c2c12d6297cdd68b6d7771cb013817 Mon Sep 17 00:00:00 2001 From: Thomas Basler Date: Sat, 18 Feb 2023 23:20:08 +0100 Subject: [PATCH 09/19] webapp: Change badge style and encapsulate it into component --- webapp/src/components/RadioInfo.vue | 32 +++++------ webapp/src/components/StatusBadge.vue | 32 +++++++++++ webapp/src/components/WifiApInfo.vue | 10 ++-- webapp/src/components/WifiStationInfo.vue | 10 ++-- webapp/src/views/MqttInfoView.vue | 67 ++++++----------------- webapp/src/views/NtpInfoView.vue | 20 +++---- 6 files changed, 82 insertions(+), 89 deletions(-) create mode 100644 webapp/src/components/StatusBadge.vue diff --git a/webapp/src/components/RadioInfo.vue b/webapp/src/components/RadioInfo.vue index 2aae902b..8f16a212 100644 --- a/webapp/src/components/RadioInfo.vue +++ b/webapp/src/components/RadioInfo.vue @@ -5,26 +5,24 @@
{{ $t('radioinfo.ChipStatus') }} - {{ $t('radioinfo.Connected') }} - {{ $t('radioinfo.NotConnected') }} + +
{{ $t('radioinfo.ChipType') }} - nRF24L01+ - nRF24L01 - {{ $t('radioinfo.Unknown') }} + + + + + +
{{ $t('wifiapinfo.Status') }} - {{ $t('wifiapinfo.Enabled') }} - {{ $t('wifiapinfo.Disabled') }} + +