123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607 |
- #include <string.h>
- #include <ctype.h>
- char *strlwr(char *str) {
- unsigned char *p = (unsigned char *)str;
- while (*p) {
- *p = tolower((unsigned char) * p);
- p++;
- }
- return str;
- }
- // MQTT callback
- void mqttCallback(char* topic, byte* payload, unsigned int length) {
- // Serial.print("MQTT payload arrived [");
- // Serial.print(topic);
- // Serial.print("] ");
- // for (int i = 0; i < length; i++) {
- // Serial.print((char)payload[i]);
- // }
- // Serial.println();
- char tmp_topic_pub[51];
- char tmp_payload_pub[51];
- if (strcmp(topic, mqtt_topic_in_cmd) == 0) { //if topic = mqtt_topic_in_cmd
- int len;
- if (length < 101) len = length; // if input is bigger than dest buffer, cut
- else len = 100;
- for (int i = 0; i < len; i++) {
- cmdPayload[i] = (char)payload[i];
- }
- //cmdPayload[len + 1] = '\0';
- cmdPayload[len] = '\0';
- // Serial.print("cmdPayload:");
- // Serial.println(cmdPayload);
- if (serialdebug) {
- Serial.print("received MQTT ");
- Serial.print(mqtt_topic_in_cmd);
- Serial.print(" - \"");
- Serial.print(cmdPayload);
- Serial.println("\"");
- }
- if (mqttdebug) {
- sprintf(tmp_topic_pub, "%s/%s", mqtt_topic_out, "mqtt_received");
- sprintf(tmp_payload_pub, "%s: %s", mqtt_topic_in_cmd, cmdPayload);
- mqttclient.publish(tmp_topic_pub, tmp_payload_pub);
- }
- cmdInQueue = true; // payload is processed in "commands"
- }//if topic = mqtt_topic_in_cmd
- if (strcmp(topic, mqtt_topic_in_setTemp) == 0) { //if topic = mqtt_topic_in_setTemp
- int len;
- if (length < 101) len = length; // if input is bigger than dest buffer, cut
- else len = 100;
- for (int i = 0; i < len; i++) {
- cmdPayload[i] = (char)payload[i];
- }
- //cmdPayload[len + 1] = '\0';
- cmdPayload[len] = '\0';
- // Serial.print("cmdPayload:");
- // Serial.println(cmdPayload);
- char tmpPayload[11];
- strlcpy(tmpPayload, cmdPayload, 10);
- float valueFloat;
- valueFloat = round(atof(tmpPayload) * 2.0) / 2.0;
- setTempTo(valueFloat);
- if (serialdebug) {
- Serial.print("received MQTT ");
- Serial.print(mqtt_topic_in_setTemp);
- Serial.print(" - \"");
- Serial.print(cmdPayload);
- Serial.println("\"");
- }
- if (mqttdebug) {
- sprintf(tmp_topic_pub, "%s/%s", mqtt_topic_out, "mqtt_received");
- sprintf(tmp_payload_pub, "%s: %s", mqtt_topic_in_setTemp, cmdPayload);
- mqttclient.publish(tmp_topic_pub, tmp_payload_pub);
- }
- cmdInQueue = false; // payload is processed in "commands"
- }//if topic = mqtt_topic_in_setTemp
- if (strcmp(topic, mqtt_topic_in_setMode) == 0) { //if topic = mqtt_topic_in_setMode
- int len;
- if (length < 101) len = length; // if input is bigger than dest buffer, cut
- else len = 100;
- for (int i = 0; i < len; i++) {
- cmdPayload[i] = (char)payload[i];
- }
- //cmdPayload[len + 1] = '\0';
- cmdPayload[len] = '\0';
- // Serial.print("cmdPayload:");
- // Serial.println(cmdPayload);
- char tmpPayload[21];
- strlcpy(tmpPayload, cmdPayload, 20);
- strlwr(tmpPayload);
- byte tmpHeatMode;
- char tmpModename0[15];
- char tmpModename1[15];
- strlcpy(tmpModename0, modename0, 14);
- strlcpy(tmpModename1, modename1, 14);
- strlwr(tmpModename0);
- strlwr(tmpModename1);
- if (strcmp(tmpPayload, tmpModename0) == 0) tmpHeatMode = 0;
- else if (strcmp(tmpPayload, tmpModename1) == 0) tmpHeatMode = 1;
- else if (strcmp(tmpPayload, "off") == 0) tmpHeatMode = 0;
- else if (strcmp(tmpPayload, "aus") == 0) tmpHeatMode = 0;
- else if (strcmp(tmpPayload, "on") == 0) tmpHeatMode = 1;
- else if (strcmp(tmpPayload, "ein") == 0) tmpHeatMode = 1;
- else if (atoi(tmpPayload) == 0) tmpHeatMode = 0;
- else if (atoi(tmpPayload) == 1) tmpHeatMode = 1;
- if (serialdebug) {
- Serial.print("set heatmode to: ");
- Serial.println(tmpHeatMode);
- }
- setHeatingmodeTo(tmpHeatMode);
- if (serialdebug) {
- Serial.print("received MQTT ");
- Serial.print(mqtt_topic_in_setMode);
- Serial.print(" - \"");
- Serial.print(cmdPayload);
- Serial.println("\"");
- }
- if (mqttdebug) {
- sprintf(tmp_topic_pub, "%s/%s", mqtt_topic_out, "mqtt_received");
- sprintf(tmp_payload_pub, "%s: %s", mqtt_topic_in_setMode, cmdPayload);
- mqttclient.publish(tmp_topic_pub, tmp_payload_pub);
- }
- cmdInQueue = false; // payload is processed in "commands"
- }//if topic = mqtt_topic_in_setMode
- if (strcmp(topic, mqtt_topic_in_setPreset) == 0) { //if topic = mqtt_topic_in_setPreset
- int len;
- if (length < 101) len = length; // if input is bigger than dest buffer, cut
- else len = 100;
- for (int i = 0; i < len; i++) {
- cmdPayload[i] = (char)payload[i];
- }
- //cmdPayload[len + 1] = '\0';
- cmdPayload[len] = '\0';
- // Serial.print("cmdPayload:");
- // Serial.println(cmdPayload);
- char tmpPayload[21];
- strlcpy(tmpPayload, cmdPayload, 20);
- strlwr(tmpPayload);
- byte tmpPreset;
- char tmpPresetName0[15];
- char tmpPresetName1[15];
- char tmpPresetName2[15];
- strlcpy(tmpPresetName0, psetname0, 14);
- strlcpy(tmpPresetName1, psetname1, 14);
- strlcpy(tmpPresetName2, psetname2, 14);
- strlwr(tmpPresetName0);
- strlwr(tmpPresetName1);
- strlwr(tmpPresetName2);
- if (strcmp(tmpPayload, tmpPresetName0) == 0) tmpPreset = 0;
- else if (strcmp(tmpPayload, tmpPresetName1) == 0) tmpPreset = 1;
- else if (strcmp(tmpPayload, tmpPresetName2) == 0) tmpPreset = 2;
- else if (strcmp(tmpPayload, "none") == 0) tmpPreset = 0;
- else if (strcmp(tmpPayload, "red1") == 0) tmpPreset = 1;
- else if (strcmp(tmpPayload, "red2") == 0) tmpPreset = 2;
- else if (atoi(tmpPayload) == 0) tmpPreset = 0;
- else if (atoi(tmpPayload) == 1) tmpPreset = 1;
- else if (atoi(tmpPayload) == 2) tmpPreset = 2;
- if (serialdebug) {
- Serial.print("set preset to: ");
- Serial.println(tmpPreset);
- }
- setPresetTo(tmpPreset);
- if (serialdebug) {
- Serial.print("received MQTT ");
- Serial.print(mqtt_topic_in_setPreset);
- Serial.print(" - \"");
- Serial.print(cmdPayload);
- Serial.println("\"");
- }
- if (mqttdebug) {
- sprintf(tmp_topic_pub, "%s/%s", mqtt_topic_out, "mqtt_received");
- sprintf(tmp_payload_pub, "%s: %s", mqtt_topic_in_setPreset, cmdPayload);
- mqttclient.publish(tmp_topic_pub, tmp_payload_pub);
- }
- cmdInQueue = false; // payload is processed in "commands"
- }//if topic = mqtt_topic_in_setPreset
- if (strcmp(topic, outTemp_topic_in) == 0) { //if topic = outTemp_topic_in
- int len;
- if (length < 6) len = length; // if input is bigger than dest buffer, cut
- else len = 5;
- for (int i = 0; i < len; i++) {
- outTemp_newValue[i] = (char)payload[i];
- }
- //outTemp_newValue[len + 1] = '\0';
- outTemp_newValue[len] = '\0';
- outTemp_parseNewValue = true;
- }//if topic = outTemp_topic_in
- if (strcmp(topic, outHum_topic_in) == 0) { //if topic = outHum_topic_in
- int len;
- if (length < 4) len = length; // if input is bigger than dest buffer, cut
- else len = 3;
- for (int i = 0; i < len; i++) {
- outHum_newValue[i] = (char)payload[i];
- }
- //outHum_newValue[len + 1] = '\0';
- outHum_newValue[len] = '\0';
- outHum_parseNewValue = true;
- }//if topic = outHum_topic_in
- if (strcmp(topic, domoticz_out_topic) == 0) { //if topic = domoticz_out_topic
- Serial.print("received MQTT ");
- Serial.println(domoticz_out_topic);
- if ( !domoticzOutParserBusy ) {
- int len;
- if (length < 450) len = length; // if input is bigger than dest buffer, cut
- else len = 449;
- for (int i = 0; i < len; i++) {
- domoticzOutPayload[i] = (char)payload[i];
- }
- //domoticzOutPayload[len + 1] = '\0';
- domoticzOutPayload[len] = '\0';
- domoticzOutParseData = true; // parse domoticz data in the next loop()
- }
- }//if topic = domoticz_out_topic
- }//mqttCallback
- void mqttPrepareConnection() {
- Serial.print("MQTT connection with ");
- if (strlen(mqtt_user) > 0 && strlen(mqtt_willTopic) == 0) {
- // user and password, no Last Will
- Serial.println("user and password, no Last Will");
- mqttMode = 2;
- }
- else if (strlen(mqtt_user) > 0 && strlen(mqtt_willTopic) > 0) {
- // user, password and Last Will
- Serial.println("user, password and Last Will");
- mqttMode = 3;
- }
- else if (strlen(mqtt_user) == 0 && strlen(mqtt_willTopic) > 0) {
- // Last Will but no user and password
- Serial.println("Last Will but no user and password");
- mqttMode = 4;
- }
- else {
- // no user, password and no Last Will
- Serial.println("no user, password and no Last Will");
- mqttMode = 1;
- }
- }
- void mqttPrepareSubscribeTopics() {
- //char tmp_topic_out[50];
- sprintf(mqtt_topic_in_cmd, "%s/%s", mqtt_topic_in, "cmd");
- sprintf(mqtt_topic_in_setTemp, "%s/%s", mqtt_topic_in_cmd, "setTemp");
- sprintf(mqtt_topic_in_setMode, "%s/%s", mqtt_topic_in_cmd, "setMode");
- sprintf(mqtt_topic_in_setPreset, "%s/%s", mqtt_topic_in_cmd, "setPreset");
- }
- boolean mqttReconnect() {
- mqttclient.disconnect();
- delay(10);
- // Create MQTT client ID from device name
- String mqttClientId = "ESP8266Client-";
- //mqttClientId += String(random(0xffff), HEX); //or random
- mqttClientId += String(deviceName);
- if (serialdebug) Serial.print("connecting to MQTT broker with ");
- boolean connRes;
- switch (mqttMode) {
- case 1:
- if (serialdebug) Serial.println("no user, password and no Last Will");
- connRes = mqttclient.connect(mqttClientId.c_str());
- break;
- case 2:
- if (serialdebug) Serial.println("user and password, no Last Will");
- connRes = mqttclient.connect(mqttClientId.c_str(), mqtt_user, mqtt_pass);
- break;
- case 3:
- if (serialdebug) Serial.println("user, password and Last Will");
- connRes = mqttclient.connect(mqttClientId.c_str(), mqtt_user, mqtt_pass, mqtt_willTopic, mqtt_willQos, mqtt_willRetain, mqtt_willMsg);
- break;
- case 4:
- if (serialdebug) Serial.println("Last Will, no user and password");
- connRes = mqttclient.connect(mqttClientId.c_str(), mqtt_willTopic, mqtt_willQos, mqtt_willRetain, mqtt_willMsg);
- break;
- }
- if (serialdebug) {
- Serial.print("... attempt: ");
- Serial.print(mqttReconnectAttempts);
- Serial.println();
- }
- if (connRes) {
- if (serialdebug) {
- Serial.print("MQTT connected. Reconnects: ");
- Serial.println(mqttReconnects);
- }
- displayShowMQTTConnected();
- mqttConnected = true;
- mqttReconnects++;
- // Once connected, publish an announcement...
- // char outMsg[30];
- // sprintf(outMsg, "connected, %d reconnects", mqttReconnects);
- // mqttclient.publish(mqtt_topic_out, outMsg, mqtt_outRetain);
- mqttclient.publish(mqtt_willTopic, mqtt_connMsg, mqtt_willRetain);
- publishStatus();
- //mqttclient.publish(mqtt_topic_out, "connected");
- // ... and resubscribe
- if (serialdebug) Serial.println("Subscribed to:");
- if (strlen(mqtt_topic_in_cmd) > 0) {
- char mqtt_topic_in_subscribe[52];
- sprintf(mqtt_topic_in_subscribe, "%s/%s", mqtt_topic_in_cmd, "#");
- if (mqttclient.subscribe(mqtt_topic_in_subscribe)) {
- if (serialdebug) Serial.println(mqtt_topic_in_subscribe);
- mqttInTopicSubscribed = true;
- }
- }
- // if (strlen(mqtt_topic_in_setTemp) > 0) {
- // if (mqttclient.subscribe(mqtt_topic_in_setTemp)) {
- // if (serialdebug) Serial.println(mqtt_topic_in_setTemp);
- // }
- // }
- // if (strlen(mqtt_topic_in_setMode) > 0) {
- // if (mqttclient.subscribe(mqtt_topic_in_setMode)) {
- // if (serialdebug) Serial.println(mqtt_topic_in_setMode);
- // }
- // }
- // if (strlen(mqtt_topic_in_setPreset) > 0) {
- // if (mqttclient.subscribe(mqtt_topic_in_setPreset)) {
- // if (serialdebug) Serial.println(mqtt_topic_in_setPreset);
- // }
- // }
- if (strlen(outTemp_topic_in) > 0) {
- if (mqttclient.subscribe(outTemp_topic_in)) {
- if (serialdebug) Serial.println(outTemp_topic_in);
- }
- }
- if (strlen(outHum_topic_in) > 0) {
- if (mqttclient.subscribe(outHum_topic_in)) {
- if (serialdebug) Serial.println(outHum_topic_in);
- }
- }
- if (useDomoticz && strlen(domoticz_out_topic) > 0) {
- if (mqttclient.subscribe(domoticz_out_topic)) {
- if (serialdebug) Serial.println(domoticz_out_topic);
- }
- }
- return mqttclient.connected();
- }
- else {
- if (serialdebug) {
- Serial.print("MQTT connect FAILED, rc=");
- Serial.println(mqttclient.state());
- }
- displayShowMQTTConnectionError();
- }
- } //mqttReconnect
- void mqttClientInit() {
- mqttclient.setServer(mqtt_server, mqtt_port);
- mqttclient.setCallback(mqttCallback);
- mqttLastReconnectAttempt = 0;
- mqttReconnectAttempts = 0;
- }
- int lastWifiStatus;
- void mqttHandleConnection() {
- int currWifiStatus = WiFi.status();
- if ( currWifiStatus != lastWifiStatus ) {
- lastWifiStatus = currWifiStatus;
- Serial.print("WiFi status changed to: ");
- Serial.println(currWifiStatus);
- }
- if ( currWifiStatus == WL_CONNECTED ) {
- // MQTT reconnect if not connected (nonblocking)
- boolean doReconnect = false;
- if (!mqttclient.connected()) doReconnect = true;
- if (mqttInTopicSubscribed) { // if mqtt_topic_in is subscribed
- if ( (millis() - mqttLastHeartbeat) > MQTT_HEARTBEAT_MAXAGE) { // also reconnect if no HEARTBEAT was received for some time
- doReconnect = true;
- mqttConnected = false;
- mqttLastHeartbeat = millis();
- Serial.println("MQTT HEARTBEAT overdue. Force-Reconnecting MQTT...");
- }
- }
- if (doReconnect) {
- unsigned int mqttReconnectAttemptDelay;
- if (mqttReconnectAttempts < 3) mqttReconnectAttemptDelay = 15000; // if this is the 1-3rd attempt, try again in 15s
- else if (mqttReconnectAttempts < 10) mqttReconnectAttemptDelay = 60000; // if more than 3 attempts failed, try again every min
- else if (mqttReconnectAttempts < 20) mqttReconnectAttemptDelay = 300000; // if more than 10 attempts failed, try again every 5 min
- else if (mqttReconnectAttempts >= 6) {
- // if more than 6 attempts (= > 30 min) failed, restart the ESP
- delay(100);
- ESP.restart();
- }
- if ((millis() - mqttLastReconnectAttempt) > mqttReconnectAttemptDelay) {
- mqttLastReconnectAttempt = millis();
- mqttReconnectAttempts++;
- if (mqttReconnect()) { // Attempt to reconnect
- // attempt successful - reset mqttReconnectAttempts
- mqttReconnectAttempts = 0;
- }
- }
- mqttclient.loop();
- }
- else {
- mqttclient.loop();
- }
- }
- }
- void publishStatus() {
- char outMsg[60];
- long upTime = millis() / 1000;
- sprintf(outMsg, "connected, reconnects: %d, uptime: %d, free heap: %d", mqttReconnects - 1, upTime, ESP.getFreeHeap());
- mqttclient.publish(mqtt_topic_out, outMsg, mqtt_outRetain);
- mqttclient.publish(mqtt_willTopic, mqtt_connMsg, mqtt_willRetain);
- yield();
- }
- void sendStatus(char* payload) {
- char buf[101];
- strlcpy(buf, payload, 101);
- Serial.println(buf);
- mqttclient.publish(mqtt_topic_out, buf, mqtt_outRetain);
- yield();
- }
- void publishCurrentThermostatValues() {
- char tmp_topic_out[50];
- updateCurrentHeatingModeName();
- updateCurrentPresetName();
- char ch_setTemp[6];
- char ch_currSetTemp[6];
- dtostrf(setTemp, 1, 1, ch_setTemp );
- dtostrf(currSetTemp, 1, 1, ch_currSetTemp );
- Serial.print("heatingMode: '");
- Serial.print(heatingMode);
- Serial.println("'");
- Serial.print("set temp: '");
- Serial.print(ch_setTemp);
- Serial.println("'");
- Serial.print("current set temp: '");
- Serial.print(ch_currSetTemp);
- Serial.println("'");
- sprintf(tmp_topic_out, "%s/%s", mqtt_topic_out, "setTemp");
- mqttclient.publish(tmp_topic_out, ch_setTemp);
- yield();
- sprintf(tmp_topic_out, "%s/%s", mqtt_topic_out, "currSetTemp");
- mqttclient.publish(tmp_topic_out, ch_currSetTemp);
- yield();
- sprintf(tmp_topic_out, "%s/%s", mqtt_topic_out, "mode");
- char ch_heatingMode[3];
- sprintf(ch_heatingMode, "%d", heatingMode);
- mqttclient.publish(tmp_topic_out, ch_heatingMode);
- sprintf(tmp_topic_out, "%s/%s", mqtt_topic_out, "modeName");
- mqttclient.publish(tmp_topic_out, currentModeName);
- sprintf(tmp_topic_out, "%s/%s", mqtt_topic_out, "preset");
- char ch_preset[3];
- sprintf(ch_preset, "%d", preset);
- mqttclient.publish(tmp_topic_out, ch_preset);
- sprintf(tmp_topic_out, "%s/%s", mqtt_topic_out, "presetName");
- mqttclient.publish(tmp_topic_out, currentPresetName);
- sprintf(tmp_topic_out, "%s/%s", mqtt_topic_out, "presetHA");
- if(preset == 0) mqttclient.publish(tmp_topic_out, "none");
- else mqttclient.publish(tmp_topic_out, currentPresetName);
- yield();
- char ch_turnHeatingOn[5];
- if (turnHeatingOn) strcpy(ch_turnHeatingOn, "on");
- else strcpy(ch_turnHeatingOn, "off");
- sprintf(tmp_topic_out, "%s/%s", mqtt_topic_out, "heating");
- mqttclient.publish(tmp_topic_out, ch_turnHeatingOn);
- yield();
- char buf[101];
- sprintf(buf, "%d", heatingOnTime);
- sprintf(tmp_topic_out, "%s/%s", mqtt_topic_out, "heatingOnTime");
- mqttclient.publish(tmp_topic_out, buf);
- yield();
- sprintf(buf, "%d", heatingOffTime);
- sprintf(tmp_topic_out, "%s/%s", mqtt_topic_out, "heatingOffTime");
- mqttclient.publish(tmp_topic_out, buf);
- yield();
- }
- void publishCurrentSensorValues() {
- if ( lastTempUpdate != 0 && (millis() - lastTempUpdate) < 120000 ) {
- char tmp_topic_out[50];
- char temp_chararr[6];
- char hum_chararr[4];
- dtostrf(currTemp, 1, 1, temp_chararr );
- sprintf(hum_chararr, "%2i", currHum);
- Serial.print("temp: '");
- Serial.print(temp_chararr);
- Serial.println("'");
- sprintf(tmp_topic_out, "%s/%s", mqtt_topic_out, "temp");
- mqttclient.publish(tmp_topic_out, temp_chararr);
- yield();
- Serial.print("hum: '");
- Serial.print(currHum);
- Serial.println("'");
- sprintf(tmp_topic_out, "%s/%s", mqtt_topic_out, "hum");
- mqttclient.publish(tmp_topic_out, hum_chararr);
- yield();
- dtostrf(currTemp_raw, 1, 1, temp_chararr );
- sprintf(hum_chararr, "%2i", currHum_raw);
- Serial.print("temp_raw: '");
- Serial.print(temp_chararr);
- Serial.println("'");
- sprintf(tmp_topic_out, "%s/%s", mqtt_topic_out, "temp_raw");
- mqttclient.publish(tmp_topic_out, temp_chararr);
- yield();
- Serial.print("hum_raw: '");
- Serial.print(currHum_raw);
- Serial.println("'");
- sprintf(tmp_topic_out, "%s/%s", mqtt_topic_out, "hum_raw");
- mqttclient.publish(tmp_topic_out, hum_chararr);
- yield();
- }
- }
- void publishCurrentPIRValue() {
- char tmp_topic_out[50];
- char PIRStatus[4];
- sprintf(tmp_topic_out, "%s/%s", mqtt_topic_out, "PIR");
- if (PIRSensorOn) {
- strcpy(PIRStatus, "on");
- }
- else {
- strcpy(PIRStatus, "off");
- }
- mqttclient.publish(tmp_topic_out, PIRStatus);
- if (strlen(mqtt_topic_pir) > 0) {
- mqttclient.publish(mqtt_topic_pir, PIRStatus);
- }
- }
- void mqttPublishHeartbeat() {
- mqttclient.publish(mqtt_topic_in_cmd, "HEARTBEAT"); // publishes to IN-topic. MQTT will force-reconnect if it does not get a HEARTBEAT for 2 min
- }
|