From 69ddf8054a727c71153b3ba200067794de13df5d Mon Sep 17 00:00:00 2001 From: Juerd Waalboer Date: Tue, 26 Jan 2021 06:28:14 +0100 Subject: [PATCH] Add basic i18n support and English translations --- README.md | 6 ++ operame.ino | 89 ++++++++++----------------- operame_strings.h | 151 ++++++++++++++++++++++++++++++++++++++++++++++ platformio.ini | 7 ++- 4 files changed, 195 insertions(+), 58 deletions(-) create mode 100644 operame_strings.h diff --git a/README.md b/README.md index 3fd7efe..a3b7a93 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,12 @@ Dit is de broncode van de firmware voor de [Operame CO2-meter](https://operame.nl/). +## Language + +The default language is Dutch; users can pick a different language using the +WiFi configuration portal. To change the default setting to English, change +`#define LANGUAGE "nl"` to `#define LANGUAGE "en"`. + ## Gebruik ### Installatie diff --git a/operame.ino b/operame.ino index c3ec65c..a8f2fcc 100644 --- a/operame.ino +++ b/operame.ino @@ -8,8 +8,10 @@ #include #include #include +#include #define LANGUAGE "nl" +OperameLanguage::Texts T; enum Driver { AQC, MHZ }; Driver driver; @@ -178,7 +180,7 @@ void connect_mqtt() { failures = 0; } else { failures++; - if (failures >= max_failures) panic("MQTT onbereikbaar"); + if (failures >= max_failures) panic(T.error_mqtt); } } @@ -258,7 +260,7 @@ int get_co2() { if (driver == MHZ) return mhz_get_co2(); // Should be unreachable - panic("driverfout"); + panic(T.error_driver); return -1; // suppress warning } @@ -280,7 +282,7 @@ void setup() { sprite.createSprite(display.width(), display.height()); while (digitalRead(pin_pcb_ok)) { - display_big("module verkeerd om!", TFT_RED); + display_big(T.error_module, TFT_RED); delay(1000); } @@ -301,32 +303,39 @@ void setup() { WiFiSettings.hostname = "operame-"; WiFiSettings.language = LANGUAGE; - wifi_enabled = WiFiSettings.checkbox("operame_wifi", false, "WiFi-verbinding gebruiken"); - ota_enabled = WiFiSettings.checkbox("operame_ota", false, "Draadloos herprogrammeren inschakelen. (Gebruikt portaalwachtwoord!)") && wifi_enabled; + WiFiSettings.begin(); + + OperameLanguage::select(T, WiFiSettings.language); + for (auto& str : T.portal_instructions[0]) { + str.replace("{ssid}", WiFiSettings.hostname); + } + + wifi_enabled = WiFiSettings.checkbox("operame_wifi", false, T.config_wifi); + ota_enabled = WiFiSettings.checkbox("operame_ota", false, T.config_ota) && wifi_enabled; WiFiSettings.heading("CO2-niveaus"); - co2_warning = WiFiSettings.integer("operame_co2_warning", 400, 5000, 700, "Geel vanaf [ppm]"); - co2_critical = WiFiSettings.integer("operame_co2_critical",400, 5000, 800, "Rood vanaf [ppm]"); - co2_blink = WiFiSettings.integer("operame_co2_blink", 800, 5000, 800, "Knipperen vanaf [ppm]"); + co2_warning = WiFiSettings.integer("operame_co2_warning", 400, 5000, 700, T.config_co2_warning); + co2_critical = WiFiSettings.integer("operame_co2_critical",400, 5000, 800, T.config_co2_critical); + co2_blink = WiFiSettings.integer("operame_co2_blink", 800, 5000, 800, T.config_co2_blink); WiFiSettings.heading("MQTT"); - mqtt_enabled = WiFiSettings.checkbox("operame_mqtt", false, "Metingen via het MQTT-protocol versturen") && wifi_enabled; - String server = WiFiSettings.string("mqtt_server", 64, "", "Broker"); - int port = WiFiSettings.integer("mqtt_port", 0, 65535, 1883, "Broker TCP-poort"); - max_failures = WiFiSettings.integer("operame_max_failures", 0, 1000, 10, "Aantal verbindingsfouten voor automatische herstart"); - mqtt_topic = WiFiSettings.string("operame_mqtt_topic", WiFiSettings.hostname, "Topic"); - mqtt_interval = 1000UL * WiFiSettings.integer("operame_mqtt_interval", 10, 3600, 60, "Publicatie-interval [s]"); - mqtt_template = WiFiSettings.string("operame_mqtt_template", "{} PPM", "Berichtsjabloon"); - WiFiSettings.info("De {} in het sjabloon wordt vervangen door de gemeten waarde."); + mqtt_enabled = WiFiSettings.checkbox("operame_mqtt", false, T.config_mqtt) && wifi_enabled; + String server = WiFiSettings.string("mqtt_server", 64, "", T.config_mqtt_server); + int port = WiFiSettings.integer("mqtt_port", 0, 65535, 1883, T.config_mqtt_port); + max_failures = WiFiSettings.integer("operame_max_failures", 0, 1000, 10, T.config_max_failures); + mqtt_topic = WiFiSettings.string("operame_mqtt_topic", WiFiSettings.hostname, T.config_mqtt_topic); + mqtt_interval = 1000UL * WiFiSettings.integer("operame_mqtt_interval", 10, 3600, 60, T.config_mqtt_interval); + mqtt_template = WiFiSettings.string("operame_mqtt_template", "{} PPM", T.config_mqtt_template); + WiFiSettings.info(T.config_template_info); WiFiSettings.onConnect = [] { - display_big("Verbinden met WiFi...", TFT_BLUE); + display_big(T.connecting, TFT_BLUE); check_portalbutton(); return 50; }; WiFiSettings.onFailure = [] { - display_big("WiFi mislukt!", TFT_RED); + display_big(T.error_wifi, TFT_RED); delay(2000); }; static int portal_phase = 0; @@ -345,44 +354,10 @@ void setup() { if (WiFi.softAPgetStationNum() == 0) portal_phase = 0; else if (! portal_phase) portal_phase = 1; - switch (portal_phase) { - case 0: { - display_lines({ - "Voor configuratie,", - "verbind met WiFi", - "\"" + WiFiSettings.hostname + "\"", - "met een smartphone." - }, TFT_WHITE, TFT_BLUE); - break ; - } - case 1: { - display_lines({ - "Volg instructies op", - "uw smartphone.", - "(inlog-notificatie)" - }, TFT_WHITE, TFT_BLUE); - break; - } - case 2: { - display_lines({ - "Wijzig instellingen", - "en klik op \"Save\".", - "(rechtsonder)" - }, TFT_WHITE, TFT_BLUE); - break; - } - case 3: { - display_lines({ - "Wijzig instellingen", - "en klik op \"Save\".", - "Of \"Restart device\"", - "als u klaar bent." - }, TFT_WHITE, TFT_BLUE); - break; - } - } + display_lines(T.portal_instructions[portal_phase], TFT_WHITE, TFT_BLUE); + if (portal_phase == 0 && millis() - portal_start > 10*60*1000) { - panic("Tijd verstreken"); + panic(T.error_timeout); } if (ota_enabled) ArduinoOTA.handle(); @@ -409,9 +384,9 @@ void loop() { every(50) { if (co2 < 0) { - display_big("sensorfout", TFT_RED); + display_big(T.error_sensor, TFT_RED); } else if (co2 == 0) { - display_big("wacht..."); + display_big(T.wait); } else { // some MH-Z19's go to 10000 but the display has space for 4 digits display_ppm(co2 > 9999 ? 9999 : co2); diff --git a/operame_strings.h b/operame_strings.h new file mode 100644 index 0000000..eb4350c --- /dev/null +++ b/operame_strings.h @@ -0,0 +1,151 @@ +#include +#include +#include + +namespace OperameLanguage { + +struct Texts { + const char + *error_mqtt, + *error_driver, + *error_module, + *error_timeout, + *error_sensor, + *error_wifi, + *config_wifi, + *config_ota, + *config_co2_warning, + *config_co2_critical, + *config_co2_blink, + *config_mqtt, + *config_mqtt_server, + *config_mqtt_port, + *config_max_failures, + *config_mqtt_topic, + *config_mqtt_interval, + *config_mqtt_template, + *config_template_info, + *connecting, + *wait + ; + std::vector> portal_instructions; +}; + +std::map languages { + // Ordered alphabetically + { "en", "English" }, + { "nl", "Nederlands" }, +}; + +bool available(const String& language) { + return languages.count(language) == 1; +} + +bool select(Texts& T, String language) { + if (! available(language)) { + if (available("en")) language = "en"; + else language = languages.begin()->first; + } + + if (language == "en") { + T.error_mqtt = "MQTT unreachable"; + T.error_driver = "driver error"; + T.error_module = "module turned around!"; + T.error_timeout = "Time's up"; + T.error_sensor = "sensor error"; + T.error_wifi = "WiFi failed!"; + T.wait = "wait..."; + T.config_wifi = "Use WiFi connection"; + T.config_ota = "Enable wireless reprogramming. (Uses portal password!)"; + T.config_co2_warning = "Yellow from [ppm]"; + T.config_co2_critical = "Red from [ppm]"; + T.config_co2_blink = "Blink from [ppm]"; + T.config_mqtt = "Publish measurements via the MQTT protocol"; + T.config_mqtt_server = "Broker"; // probably should not be translated + T.config_mqtt_port = "Broker TCP port"; + T.config_max_failures = "Number of failed connections before automatic restart"; + T.config_mqtt_topic = "Topic"; // probably should not be translated + T.config_mqtt_interval = "Publication interval [s]"; + T.config_mqtt_template = "Message template"; + T.config_template_info = "The {} in the template is replaced by the measurement value."; + T.connecting = "Connecting to WiFi..."; + T.portal_instructions = { + { + "For configuration,", + "connect to WiFi", + "\"{ssid}\"", + "with a smartphone." + }, + { + "Follow instructions", + "on your smartphone.", + "(log in notification)" + }, + { + "Change settings", + "and click \"Save\".", + "(bottom right)" + }, + { + "Change settings", + "and click \"Save\".", + "Or \"Restart device\"", + "when you're done." + } + }; + return true; + } + + if(language == "nl") { + T.error_mqtt = "MQTT onbereikbaar"; + T.error_driver = "driverfout"; + T.error_module = "module verkeerd om!"; + T.error_timeout = "Tijd verstreken"; + T.error_sensor = "sensorfout"; + T.error_wifi = "WiFi mislukt!"; + T.wait = "wacht..."; + T.config_wifi = "WiFi-verbinding gebruiken"; + T.config_ota = "Draadloos herprogrammeren inschakelen. (Gebruikt portaalwachtwoord!)"; + T.config_co2_warning = "Geel vanaf [ppm]"; + T.config_co2_critical = "Rood vanaf [ppm]"; + T.config_co2_blink = "Knipperen vanaf [ppm]"; + T.config_mqtt = "Metingen via het MQTT-protocol versturen"; + T.config_mqtt_server = "Broker"; // zo heet dat in MQTT + T.config_mqtt_port = "Broker TCP-poort"; + T.config_max_failures = "Aantal verbindingsfouten voor automatische herstart"; + T.config_mqtt_topic = "Topic"; // zo heet dat in MQTT + T.config_mqtt_interval = "Publicatie-interval [s]"; + T.config_mqtt_template = "Berichtsjabloon"; + T.config_template_info = "De {} in het sjabloon wordt vervangen door de gemeten waarde."; + T.connecting = "Verbinden met WiFi..."; + T.portal_instructions = { + { + "Voor configuratie,", + "verbind met WiFi", + "\"{ssid}\"", + "met een smartphone." + }, + { + "Volg instructies op", + "uw smartphone.", + "(inlog-notificatie)" + }, + { + "Wijzig instellingen", + "en klik op \"Opslaan\".", + "(rechtsonder)" + }, + { + "Wijzig instellingen", + "en klik op \"Opslaan\".", + "Of \"Herstarten\"", + "als u klaar bent." + } + }; + return true; + } + + return false; +} + +} // namespace diff --git a/platformio.ini b/platformio.ini index 927db8a..ba61e1f 100644 --- a/platformio.ini +++ b/platformio.ini @@ -21,13 +21,18 @@ framework = arduino targets = upload monitor_speed = 115200 lib_deps = - ESP-WiFiSettings@^3.7 + ESP-WiFiSettings@^3.7.2 MH-Z19 TFT_eSPI MQTT build_flags = +# ESP-WiFiSettings languages: + -DLANGUAGE_EN + -DLANGUAGE_NL +# ESP32 debugging: # -DCORE_DEBUG_LEVEL=5 +# TFT_eSPI configuration: -DUSER_SETUP_LOADED=1 -DST7789_DRIVER=1 -DCGRAM_OFFSET=1