mirror of
				https://github.com/revspace/operame
				synced 2025-10-31 03:25:37 +00:00 
			
		
		
		
	Compare commits
	
		
			11 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | b84a6d8b19 | ||
|  | 2807ee2647 | ||
|  | 8fa0ee91e7 | ||
|  | 29d873d268 | ||
|  | 69ddf8054a | ||
|  | f76e092998 | ||
|  | d1942fcaa0 | ||
|  | 7fb7682cfe | ||
|  | e92b3f6bb2 | ||
|  | 3f87f63951 | ||
|  | 216534d105 | 
| @ -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 | ||||
|  | ||||
							
								
								
									
										87
									
								
								multi-upload.pl
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								multi-upload.pl
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,87 @@ | ||||
| #!/usr/bin/perl | ||||
| use strict; | ||||
| use warnings; | ||||
| use autodie; | ||||
| use Time::HiRes qw(sleep); | ||||
| use POSIX qw(strftime); | ||||
| 
 | ||||
| if (!@ARGV or $ARGV[0] ne "--please-destroy-my-data") { | ||||
|     print "DANGER! Please read and understand the source code before using.\n"; | ||||
|     print "Regular users do not need to use this program. Use 'pio run' instead.\n"; | ||||
|     exit 1; | ||||
| } | ||||
| 
 | ||||
| my %pane; | ||||
| my $command = ""; | ||||
| 
 | ||||
| sub printlog { | ||||
|     print strftime("%Y-%m-%d %H:%M:%S", localtime), " @_\n"; | ||||
| } | ||||
| 
 | ||||
| sub spawn { | ||||
|     my ($dev) = @_; | ||||
| 
 | ||||
|     printlog "Spawning $dev"; | ||||
| 
 | ||||
|     my $c = $command; | ||||
| 
 | ||||
|     $c =~ s[ttyUSB\w+][$dev]; | ||||
|     $c =~ s/^/time /; | ||||
|     $c =~ s[$][| perl -pe"BEGIN { \$/ = \\1 } s/\\r/\\n/"; echo "-- $dev done --"; read a]; | ||||
| 
 | ||||
|     $pane{$dev} = readpipe qq{tmux split-window -d -h -P -F '#{pane_id}' '$c'}; | ||||
|     chomp $pane{$dev}; | ||||
| 
 | ||||
|     system "tmux select-layout even-horizontal"; | ||||
| } | ||||
| 
 | ||||
| if (1 < (() = glob("/dev/ttyUSB*"))) { | ||||
|     die "Disconnect USB serial devices except one target device.\n"; | ||||
| } | ||||
| 
 | ||||
| if ($ARGV[-1] ne "it's-a-me") { | ||||
|     exec qw[tmux new perl], $0, @ARGV, "it's-a-me"; | ||||
| } | ||||
| 
 | ||||
| my $pio_pid = open my $pio, "-|", "pio run -v -t upload"; | ||||
| while (defined(my $line = readline $pio)) { | ||||
|     print $line; | ||||
|     if ($line =~ /esptool/ && $line =~ /write_flash/) { | ||||
|         $command = $line; | ||||
|         system "pkill -9 -P $pio_pid";  # kill upload process. | ||||
|         kill 9, $pio_pid; | ||||
|         last; | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| if ($command =~ /(ttyUSB\d+)/) { | ||||
|     spawn $1; | ||||
| } else { | ||||
|     warn "Could not snatch upload command.\nMake sure a single target device is already connected.\nPress enter to exit.\n"; | ||||
|     scalar <STDIN>; | ||||
|     die; | ||||
| } | ||||
| 
 | ||||
| open my $monitor, "-|", "udevadm monitor --kernel --subsystem-match=usb-serial"; | ||||
| 
 | ||||
| printlog "Started monitoring for new usb-serial devices."; | ||||
| 
 | ||||
| 
 | ||||
| while (defined(my $line = readline $monitor)) { | ||||
|     my ($event) = $line =~ /\b(remove|add)\b/ or next; | ||||
|     my ($dev) = $line =~ /(ttyUSB\d+)/ or next; | ||||
| 
 | ||||
|     if ($event eq 'add') { | ||||
|         while (!-w "/dev/$dev") { | ||||
|             sleep .1; | ||||
|             # wait for permissions to settle; | ||||
|         } | ||||
| 
 | ||||
|         spawn($dev); | ||||
|     } else { | ||||
|         if (exists $pane{$dev}) { | ||||
|             printlog "Killing $dev"; | ||||
|             system "tmux kill-pane -t $pane{$dev}"; | ||||
|         } | ||||
|     } | ||||
| } | ||||
							
								
								
									
										189
									
								
								operame.ino
									
									
									
									
									
								
							
							
						
						
									
										189
									
								
								operame.ino
									
									
									
									
									
								
							| @ -8,6 +8,10 @@ | ||||
| #include <TFT_eSPI.h> | ||||
| #include <logo.h> | ||||
| #include <list> | ||||
| #include <operame_strings.h> | ||||
| 
 | ||||
| #define LANGUAGE "nl" | ||||
| OperameLanguage::Texts T; | ||||
| 
 | ||||
| enum Driver { AQC, MHZ }; | ||||
| Driver          driver; | ||||
| @ -109,11 +113,31 @@ void display_ppm(int ppm) { | ||||
|     display_big(String(ppm), fg, bg); | ||||
| } | ||||
| 
 | ||||
| void calibrate() { | ||||
|     auto lines = T.calibration; | ||||
|     for (int count = 60; count >= 0; count--) { | ||||
|         lines.back() = String(count); | ||||
|         display_lines(lines, TFT_RED); | ||||
|         unsigned long start = millis(); | ||||
|         while (millis() - start < 1000) { | ||||
|             if (button(pin_demobutton) || button(pin_portalbutton)) return; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     lines = T.calibrating; | ||||
|     if (driver == AQC) for (auto& line : lines) line.replace("400", "425"); | ||||
|     display_lines(lines, TFT_MAGENTA); | ||||
| 
 | ||||
|     set_zero();    // actually instantaneous
 | ||||
|     delay(15000);  // give time to read long message
 | ||||
| } | ||||
| 
 | ||||
| void ppm_demo() { | ||||
|     display_big("demo!"); | ||||
|     delay(3000); | ||||
|     display_logo(); | ||||
|     delay(1000); | ||||
|     int buttoncounter = 0; | ||||
|     for (int p = 400; p < 1200; p++) { | ||||
|         display_ppm(p); | ||||
|         if (button(pin_demobutton)) { | ||||
| @ -121,6 +145,18 @@ void ppm_demo() { | ||||
|             delay(500); | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         // Hold portal button from 700 to 800 for manual calibration
 | ||||
|         if (p >= 700 && p < 800 && !digitalRead(pin_portalbutton)) { | ||||
|             buttoncounter++; | ||||
|         } | ||||
|         if (p == 800 && buttoncounter >= 85) { | ||||
|             while (!digitalRead(pin_portalbutton)) delay(100); | ||||
|             calibrate(); | ||||
|             display_logo(); | ||||
|             delay(500); | ||||
|             return; | ||||
|         } | ||||
|         delay(30); | ||||
|     } | ||||
|     display_logo(); | ||||
| @ -176,10 +212,17 @@ void connect_mqtt() { | ||||
|         failures = 0; | ||||
|     } else { | ||||
|         failures++; | ||||
|         if (failures >= max_failures) panic("MQTT onbereikbaar"); | ||||
|         if (failures >= max_failures) panic(T.error_mqtt); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| void flush(Stream& s, int limit = 20) { | ||||
|     // .available() sometimes stays true (why?), hence the limit
 | ||||
| 
 | ||||
|     s.flush();  // flush output
 | ||||
|     while(s.available() && --limit) s.read();  // flush input
 | ||||
| } | ||||
| 
 | ||||
| int aqc_get_co2() { | ||||
|     static bool initialized = false; | ||||
| 
 | ||||
| @ -188,12 +231,10 @@ int aqc_get_co2() { | ||||
|     int co2 = -1; | ||||
| 
 | ||||
|     for (int attempt = 0; attempt < 3; attempt++) { | ||||
|         hwserial1.flush(); | ||||
|         int limit = 20;  // .available() sometimes stays true
 | ||||
|         while(hwserial1.available() && --limit) hwserial1.read(); | ||||
| 
 | ||||
|         flush(hwserial1); | ||||
|         hwserial1.write(command, sizeof(command)); | ||||
|         delay(50); | ||||
| 
 | ||||
|         size_t c = hwserial1.readBytes(response, sizeof(response)); | ||||
|         if (c != sizeof(response) || response[0] != 0xff || response[1] != 0x86) { | ||||
|             continue; | ||||
| @ -219,6 +260,12 @@ int aqc_get_co2() { | ||||
|     return co2; | ||||
| } | ||||
| 
 | ||||
| void aqc_set_zero() { | ||||
|     const uint8_t command[9] = { 0xff, 0x01, 0x87, 0, 0, 0, 0, 0, 0x78 }; | ||||
|     flush(hwserial1); | ||||
|     hwserial1.write(command, sizeof(command)); | ||||
| } | ||||
| 
 | ||||
| void mhz_setup() { | ||||
|     mhz.begin(hwserial1); | ||||
|     // mhz.setFilter(true, true);  Library filter doesn't handle 0436
 | ||||
| @ -249,6 +296,10 @@ int mhz_get_co2() { | ||||
|     return co2; | ||||
| } | ||||
| 
 | ||||
| void mhz_set_zero() { | ||||
|     mhz.calibrate(); | ||||
| } | ||||
| 
 | ||||
| int get_co2() { | ||||
|     // <0 means read error, 0 means still initializing, >0 is PPM value
 | ||||
| 
 | ||||
| @ -256,32 +307,56 @@ int get_co2() { | ||||
|     if (driver == MHZ) return mhz_get_co2(); | ||||
| 
 | ||||
|     // Should be unreachable
 | ||||
|     panic("driverfout"); | ||||
|     panic(T.error_driver); | ||||
|     return -1;  // suppress warning
 | ||||
| } | ||||
| 
 | ||||
| void set_zero() { | ||||
|     if (driver == AQC) { aqc_set_zero(); return; } | ||||
|     if (driver == MHZ) { mhz_set_zero(); return; } | ||||
| 
 | ||||
|     // Should be unreachable
 | ||||
|     panic(T.error_driver); | ||||
| } | ||||
| 
 | ||||
| void setup() { | ||||
|     Serial.begin(115200); | ||||
|     Serial.println("Operame start"); | ||||
|     SPIFFS.begin(true); | ||||
| 
 | ||||
|     digitalWrite(pin_backlight, HIGH); | ||||
|     display.init(); | ||||
|     display.fillScreen(TFT_BLACK); | ||||
|     display.setRotation(1); | ||||
|     sprite.createSprite(display.width(), display.height()); | ||||
| 
 | ||||
|     OperameLanguage::select(T, LANGUAGE); | ||||
| 
 | ||||
|     if (!SPIFFS.begin(false)) { | ||||
|         display_lines(T.first_run, TFT_MAGENTA); | ||||
|         if (!SPIFFS.format()) { | ||||
|             display_big(T.error_format, TFT_RED); | ||||
|             delay(20*1000); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pinMode(pin_portalbutton,   INPUT_PULLUP); | ||||
|     pinMode(pin_demobutton,     INPUT_PULLUP); | ||||
|     pinMode(pin_pcb_ok,         INPUT_PULLUP); | ||||
|     pinMode(pin_backlight,      OUTPUT); | ||||
| 
 | ||||
|     digitalWrite(pin_backlight, HIGH); | ||||
| 
 | ||||
|     display.init(); | ||||
|     display.fillScreen(TFT_BLACK); | ||||
|     display.setRotation(1); | ||||
|     sprite.createSprite(display.width(), display.height()); | ||||
|     WiFiSettings.hostname = "operame-"; | ||||
|     WiFiSettings.language = LANGUAGE; | ||||
|     WiFiSettings.begin(); | ||||
|     OperameLanguage::select(T, WiFiSettings.language); | ||||
| 
 | ||||
|     while (digitalRead(pin_pcb_ok)) { | ||||
|         display_big("module verkeerd om!", TFT_RED); | ||||
|         display_big(T.error_module, TFT_RED); | ||||
|         delay(1000); | ||||
|     } | ||||
| 
 | ||||
|     display_logo(); | ||||
|     delay(2000); | ||||
| 
 | ||||
|     hwserial1.begin(9600, SERIAL_8N1, pin_sensor_rx, pin_sensor_tx); | ||||
| 
 | ||||
|     if (aqc_get_co2() >= 0) { | ||||
| @ -294,42 +369,42 @@ void setup() { | ||||
|         Serial.println("Using MHZ driver."); | ||||
|     } | ||||
| 
 | ||||
|     display_logo(); | ||||
|     delay(2000); | ||||
| 
 | ||||
|     WiFiSettings.hostname = "operame-"; | ||||
|     wifi_enabled  = WiFiSettings.checkbox("operame_wifi", false, "WiFi-verbinding gebruiken"); | ||||
|     ota_enabled   = WiFiSettings.checkbox("operame_ota", false, "Draadloos herprogrammeren inschakelen. (Gebruikt portaalwachtwoord!)") && wifi_enabled; | ||||
|     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; | ||||
|     static unsigned long portal_start; | ||||
|     WiFiSettings.onPortal = [] { | ||||
|         if (ota_enabled) setup_ota; | ||||
|         if (ota_enabled) setup_ota(); | ||||
|         portal_start = millis(); | ||||
|     }; | ||||
|     WiFiSettings.onPortalView = [] { | ||||
| @ -342,44 +417,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(); | ||||
| @ -394,7 +435,7 @@ void setup() { | ||||
|     if (ota_enabled) setup_ota(); | ||||
| } | ||||
| 
 | ||||
| #define every(t) for (static uint16_t _lasttime; (uint16_t)((uint16_t)millis() - _lasttime) >= (t); _lasttime = millis()) | ||||
| #define every(t) for (static unsigned long _lasttime; (unsigned long)((unsigned long)millis() - _lasttime) >= (t); _lasttime = millis()) | ||||
| 
 | ||||
| void loop() { | ||||
|     static int co2; | ||||
| @ -406,9 +447,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); | ||||
|  | ||||
							
								
								
									
										191
									
								
								operame_strings.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										191
									
								
								operame_strings.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,191 @@ | ||||
| #include <map> | ||||
| #include <vector> | ||||
| #include <list> | ||||
| 
 | ||||
| namespace OperameLanguage { | ||||
| 
 | ||||
| struct Texts { | ||||
|     const char | ||||
|         *error_mqtt, | ||||
|         *error_driver, | ||||
|         *error_module, | ||||
|         *error_timeout, | ||||
|         *error_sensor, | ||||
|         *error_wifi, | ||||
|         *error_format, | ||||
|         *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<std::list<String>> portal_instructions; | ||||
|     std::list<String> first_run; | ||||
|     std::list<String> calibration; | ||||
|     std::list<String> calibrating; | ||||
| }; | ||||
| 
 | ||||
| std::map<const String, const String> 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.error_format = "Formatting 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." | ||||
|             } | ||||
|         }; | ||||
|         T.first_run = { | ||||
|             "DO NOT TURN OFF", | ||||
|             "Initializing", | ||||
|             "flash memory.", | ||||
|         }; | ||||
|         T.calibration = { | ||||
|             "Manual calibration!", | ||||
|             "Press button", | ||||
|             "to cancel.", | ||||
|             "" | ||||
|         }; | ||||
|         T.calibrating = { | ||||
|             "Assuming current", | ||||
|             "CO2 level to be", | ||||
|             "400 PPM." | ||||
|         }; | ||||
|         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.error_format = "Formatteren 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." | ||||
|             } | ||||
|         }; | ||||
|         T.first_run = { | ||||
|             "NIET", | ||||
|             "UITSCHAKELEN", | ||||
|             "Flashgeheugen", | ||||
|             "wordt voorbereid." | ||||
|         }; | ||||
|         T.calibration = { | ||||
|             "Handmatige", | ||||
|             "calibratie!", | ||||
|             "knop = stop", | ||||
|             "" | ||||
|         }; | ||||
|         T.calibrating = { | ||||
|             "Het huidige CO2-", | ||||
|             "niveau wordt", | ||||
|             "aangenomen", | ||||
|             "400 PPM te zijn." | ||||
|         }; | ||||
|         return true; | ||||
|     } | ||||
| 
 | ||||
|     return false; | ||||
| } | ||||
| 
 | ||||
| } // namespace
 | ||||
| @ -21,13 +21,18 @@ framework = arduino | ||||
| targets = upload | ||||
| monitor_speed = 115200 | ||||
| lib_deps = | ||||
|     ESP-WiFiSettings @^3.6 | ||||
|     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 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user