diff --git a/docs/upload/web-install.md b/docs/upload/web-install.md index 5039d45..300ad92 100644 --- a/docs/upload/web-install.md +++ b/docs/upload/web-install.md @@ -6,8 +6,9 @@ If you want to use the BLE decoding capabilities of OpenMQTTGateway with a tablet or smartphone you can use [Theengs App](https://app.theengs.io/). ::: -::: NOTE +::: warning Note If you are on macOS and have a LilyGo LoRa32 V2.1 board, make sure you have the [correct driver for the CH9102 Serial Chip](https://github.com/WCHSoftGroup/ch34xser_macos) installed and selected in the popup when initiating the web install. +::: To finalise the driver installation don't forget the confirmation in the **Security** section of **System Preferences** after the restart. diff --git a/docs/use/displays.md b/docs/use/displays.md index 4def0f8..3c60c69 100644 --- a/docs/use/displays.md +++ b/docs/use/displays.md @@ -84,3 +84,25 @@ You can also change it by MQTT. For example if you want to display module json m And to disable the display of module json messages: `mosquitto_pub -t home/OpenMQTTGateway/commands/MQTTtoSSD1306/config -m '{"display-json":false}'` + +### Store the current display configuration in the gateway + +To store the running display configuration into non-volatile storage on the gateway use the following command. This assures persistence across restarts. + +`mosquitto_pub -t home/OpenMQTTGateway/commands/MQTTtoSSD1306/config -m '{"save":true}'` + +At any time, you can reload the stored configuration with the command: + +`mosquitto_pub -t home/OpenMQTTGateway/commands/MQTTtoSSD1306/config -m '{"load":true}'` + +If you want to erase the stored configuration, use the command: + +`mosquitto_pub -t home/OpenMQTTGateway/commands/MQTTtoSSD1306/config -m '{"erase":true}'` + +Note that this will not change the running configuration, it only ensures that the default configuration is used at next startup. + +If you want to load the default configuration use the command: + +`mosquitto_pub -t home/OpenMQTTGateway/commands/MQTTtoSSD1306/config -m '{"init":true}'` + +Note that this will not change the stored configuration, `erase` or `save` is still needed to overwrite the saved configuration. diff --git a/main/ZdisplaySSD1306.ino b/main/ZdisplaySSD1306.ino index e96f349..fdccc67 100644 --- a/main/ZdisplaySSD1306.ino +++ b/main/ZdisplaySSD1306.ino @@ -47,7 +47,7 @@ boolean displayMetric = DISPLAY_METRIC; boolean displayFlip = DISPLAY_FLIP; boolean displayState = DISPLAY_STATE; boolean idlelogo = DISPLAY_IDLE_LOGO; -uint8_t displayBrightness = round(DISPLAY_BRIGHTNESS * 2.55); +uint8_t displayBrightness = DISPLAY_BRIGHTNESS; /* Toogle log display @@ -70,6 +70,8 @@ void setupSSD1306() { Log.trace(F("ZdisplaySSD1306 DISPLAY_METRIC: %T" CR), displayMetric); Log.trace(F("ZdisplaySSD1306 DISPLAY_FLIP: %T" CR), displayFlip); + SSD1306Config_init(); + SSD1306Config_load(); Oled.begin(); Log.notice(F("Setup SSD1306 Display end" CR)); @@ -125,10 +127,10 @@ void MQTTtoSSD1306(char* topicOri, JsonObject& SSD1306data) { // json object dec bool success = false; if (cmpToMainTopic(topicOri, subjectMQTTtoSSD1306set)) { Log.trace(F("MQTTtoSSD1306 json set" CR)); - // Log display set between SSD1306 OLED (true) and serial monitor (false) + // properties if (SSD1306data.containsKey("onstate")) { if (displayState != SSD1306data["onstate"]) { - displayState = SSD1306data["onstate"]; + displayState = SSD1306data["onstate"].as(); if (!displayState) { Oled.display->displayOff(); } else { @@ -136,17 +138,19 @@ void MQTTtoSSD1306(char* topicOri, JsonObject& SSD1306data) { // json object dec Oled.begin(); } } - displayState = SSD1306data["onstate"]; - Log.notice(F("Set display state: %T" CR), logToOLEDDisplay); + displayState = SSD1306data["onstate"].as(); + Log.notice(F("Set display state: %T" CR), displayState); success = true; - } else if (SSD1306data.containsKey("brightness")) { - displayBrightness = SSD1306data["brightness"]; - displayBrightness = round(displayBrightness * 2.55); - Oled.display->setBrightness(displayBrightness); + } + if (SSD1306data.containsKey("brightness")) { + displayBrightness = SSD1306data["brightness"].as(); + Oled.display->setBrightness(round(displayBrightness * 2.55)); + Oled.begin(); Log.notice(F("Set brightness: %d" CR), displayBrightness); success = true; - } else if (SSD1306data.containsKey("log-oled")) { - logToOLEDDisplay = SSD1306data["log-oled"]; + } + if (SSD1306data.containsKey("log-oled")) { + logToOLEDDisplay = SSD1306data["log-oled"].as(); Log.notice(F("Set OLED log: %T" CR), logToOLEDDisplay); logToOLED(logToOLEDDisplay); if (logToOLEDDisplay) { @@ -154,22 +158,25 @@ void MQTTtoSSD1306(char* topicOri, JsonObject& SSD1306data) { // json object dec } success = true; } else if (SSD1306data.containsKey("json-oled")) { - jsonDisplay = SSD1306data["json-oled"]; + jsonDisplay = SSD1306data["json-oled"].as(); if (jsonDisplay) { logToOLEDDisplay = false; logToOLED(logToOLEDDisplay); } Log.notice(F("Set json-oled: %T" CR), jsonDisplay); success = true; - } else if (SSD1306data.containsKey("display-metric")) { - displayMetric = SSD1306data["display-metric"]; + } + if (SSD1306data.containsKey("display-metric")) { + displayMetric = SSD1306data["display-metric"].as(); Log.notice(F("Set display-metric: %T" CR), displayMetric); success = true; - } else if (SSD1306data.containsKey("idlelogo")) { - idlelogo = SSD1306data["idlelogo"]; + } + if (SSD1306data.containsKey("idlelogo")) { + idlelogo = SSD1306data["idlelogo"].as(); success = true; - } else if (SSD1306data.containsKey("display-flip")) { - displayFlip = SSD1306data["display-flip"]; + } + if (SSD1306data.containsKey("display-flip")) { + displayFlip = SSD1306data["display-flip"].as(); Log.notice(F("Set display-flip: %T" CR), displayFlip); if (displayFlip) { Oled.display->flipScreenVertically(); @@ -178,6 +185,38 @@ void MQTTtoSSD1306(char* topicOri, JsonObject& SSD1306data) { // json object dec } success = true; } + // save, load, init, erase + if (SSD1306data.containsKey("save") && SSD1306data["save"]) { + success = SSD1306Config_save(); + if (success) { + Log.notice(F("SSD1306 config saved" CR)); + pub(subjectSSD1306toMQTT, "{\"Status\": \"SSD1306 configs saved\"}"); + } + } else if (SSD1306data.containsKey("load") && SSD1306data["load"]) { + success = SSD1306Config_load(); + if (success) { + Log.notice(F("SSD1306 config loaded" CR)); + pub(subjectSSD1306toMQTT, "{\"Status\": \"SSD1306 configs loaded\"}"); + Oled.begin(); + } + } else if (SSD1306data.containsKey("init") && SSD1306data["init"]) { + SSD1306Config_init(); + pub(subjectSSD1306toMQTT, "{\"Status\": \"SSD1306 configs initialised\"}"); + Oled.begin(); + success = true; + } else if (SSD1306data.containsKey("erase") && SSD1306data["erase"]) { + // Erase config from NVS (non-volatile storage) + preferences.begin(Gateway_Short_Name, false); + success = preferences.remove("SSD1306Config"); + preferences.end(); + if (success) { + Log.notice(F("SSD1306 config erased" CR)); + pub(subjectSSD1306toMQTT, "{\"Status\": \"SSD1306 configs erased\"}"); + } else { + Log.notice(F("SSD1306 nothing to erase" CR)); + pub(subjectSSD1306toMQTT, "{\"Status\": \"SSD1306 nothing to erase\"}"); + } + } if (success) { stateSSD1306Display(); } else { @@ -187,6 +226,66 @@ void MQTTtoSSD1306(char* topicOri, JsonObject& SSD1306data) { // json object dec } } +bool SSD1306Config_save() { + StaticJsonDocument jsonBuffer; + JsonObject jo = jsonBuffer.to(); + jo["onstate"] = displayState; + jo["brightness"] = displayBrightness; + jo["log-oled"] = logToOLEDDisplay; + jo["json-oled"] = jsonDisplay; + jo["display-metric"] = displayMetric; + jo["idlelogo"] = idlelogo; + jo["display-flip"] = displayFlip; + // Save config into NVS (non-volatile storage) + String conf = ""; + serializeJson(jsonBuffer, conf); + preferences.begin(Gateway_Short_Name, false); + preferences.putString("SSD1306Config", conf); + preferences.end(); +} + +void SSD1306Config_init() { + displayState = DISPLAY_STATE; + displayBrightness = DISPLAY_BRIGHTNESS; + logToOLEDDisplay = LOG_TO_OLED; + jsonDisplay = JSON_TO_OLED; + displayMetric = DISPLAY_METRIC; + idlelogo = DISPLAY_IDLE_LOGO; + displayFlip = DISPLAY_FLIP; + Log.notice(F("SSD1306 config initialised" CR)); +} + +bool SSD1306Config_load() { + StaticJsonDocument jsonBuffer; + preferences.begin(Gateway_Short_Name, true); + String exists = preferences.getString("SSD1306Config", "{}"); + if (exists != "{}") { + auto error = deserializeJson(jsonBuffer, preferences.getString("SSD1306Config", "{}")); + preferences.end(); + if (error) { + Log.error(F("SSD1306 config deserialization failed: %s, buffer capacity: %u" CR), error.c_str(), jsonBuffer.capacity()); + return false; + } + if (jsonBuffer.isNull()) { + Log.warning(F("SSD1306 config is null" CR)); + return false; + } + JsonObject jo = jsonBuffer.as(); + displayState = jo["onstate"].as(); + displayBrightness = jo["brightness"].as(); + logToOLEDDisplay = jo["log-oled"].as(); + jsonDisplay = jo["json-oled"].as(); + displayMetric = jo["display-metric"].as(); + idlelogo = jo["idlelogo"].as(); + displayFlip = jo["display-flip"].as(); + return true; + } else { + preferences.end(); + Log.notice(F("No SSD1306 config to load" CR)); + return false; + } +} + /* Workaround for c not having a string based switch/case function */ @@ -777,19 +876,19 @@ void OledSerial::begin() { xSemaphoreGive(semaphoreOLEDOperation); display->init(); - if (displayState) { - if (displayFlip) { - display->flipScreenVertically(); - } else { - display->resetOrientation(); - } - display->setFont(ArialMT_Plain_10); - display->setBrightness(displayBrightness); - drawLogo(0, 0); - display->invertDisplay(); - display->setLogBuffer(OLED_TEXT_ROWS, OLED_TEXT_BUFFER); - delay(1000); + if (displayFlip) { + display->flipScreenVertically(); } else { + display->resetOrientation(); + } + display->setFont(ArialMT_Plain_10); + display->setBrightness(round(displayBrightness * 2.55)); + drawLogo(0, 0); + display->invertDisplay(); + display->setLogBuffer(OLED_TEXT_ROWS, OLED_TEXT_BUFFER); + delay(1000); + + if (!displayState) { display->displayOff(); } } @@ -923,7 +1022,7 @@ void stateSSD1306Display() { StaticJsonDocument jsonBuffer; JsonObject DISPLAYdata = jsonBuffer.to(); DISPLAYdata["onstate"] = (bool)displayState; - DISPLAYdata["brightness"] = (int)round(displayBrightness / 2.55); + DISPLAYdata["brightness"] = (int)displayBrightness; DISPLAYdata["display-metric"] = (bool)displayMetric; DISPLAYdata["display-flip"] = (bool)displayFlip; DISPLAYdata["idlelogo"] = (bool)idlelogo;