Forum Replies Created
-
AuthorPosts
-
Here is the code with the ArduinoThingIO. I get the following error:
In file included from Documents\Arduino\libraries\ArduinoIoTCloud\src/ArduinoIoTCloudTCP.h:30:0,
from Documents\Arduino\libraries\ArduinoIoTCloud\src/ArduinoIoTCloud.h:169,
Taps_logger_One_Beer_Later\thingProperties.h:5,
Taps_logger_One_Beer_Later\Taps_logger_One_Beer_Later.ino:21:
Documents\Arduino\libraries\ArduinoIoTCloud\src/tls/utility/TLSClientMqtt.h:39:12: fatal error: ArduinoBearSSL.h: No such file or directory
#include <ArduinoBearSSL.h>
^~~~~~~~~~~~~~~~~~
compilation terminated.
exit status 1
Compilation error: exit status 1/* Libraries needed for Arduino Giga R1 WiFi (NOT Zephyr): Arduino_Portenta_OTA ArduinoECCX08 ArduinoIoTCloud ArduinoHttpClient ArduinoMqttClient Arduino_NetworkConfigurator // 10/12/25 Arduino_SecureElement // 10/12/25 Arduino_ConnectionHandler Arduino_DebugUtils Arduino_USBHostMbed5 EMailSender - ONLY WITH THIS BRANCH: https://github.com/xreef/EMailSender/tree/ArduinoGIGATest?tab=readme-ov-file FlowSensor-Arduino NTPClient */ #define DEBUG 0 // Set to 1 for DEBUG // ArduinoIoTCloud #include "thingProperties.h" // incompatibility with EmailSender.h // FlowSensor #include <Arduino.h> #include <FlowSensor.h> // WiFi #include "arduino_secrets.h" #include <WiFi.h> // NTP time #include <NTPClient.h> // from Arduino Opta??? #include <WiFiUdp.h> #include <mbed_mktime.h> // USB Type-A storage #include <Arduino_USBHostMbed5.h> #include <DigitalOut.h> #include <FATFileSystem.h> // eMail #include <EMailSender.h> // FlowSensor #define type YFS201 // Arduino Giga R1 Wifi: limited to 15/16 interrupts at the same time const byte interruptPinSensorFlowTap1 = 2; // interrupt pin const byte interruptPinSensorFlowTap2 = 3; // interrupt pin const byte interruptPinSensorFlowTap3 = 5; // interrupt pin const byte interruptPinSensorFlowTap4 = 6; // interrupt pin const byte interruptPinSensorFlowTap5 = 7; // interrupt pin const byte interruptPinSensorFlowTap6 = 10; // interrupt pin const byte interruptPinSensorFlowTap7 = 11; // interrupt pin const byte interruptPinSensorFlowTap8 = 12; // interrupt pin const byte interruptPinSensorFlowTap9 = 13; // interrupt pin const byte interruptPinSensorFlowTap10 = 14; // interrupt pin const byte interruptPinSensorFlowTap11 = 17; // interrupt pin const byte interruptPinSensorFlowTap12 = 18; // interrupt pin const byte interruptPinSensorFlowTap13 = 22; // interrupt pin const byte interruptPinSensorFlowTap14 = 25; // interrupt pin const byte interruptPinSensorFlowTap15 = 28; // interrupt pin FlowSensor SensorFlowTap1(type, interruptPinSensorFlowTap1); // LED #define LED_BUILTIN_GREEN D87 #define LED_BUILTIN_BLUE D88 // WiFi // Enter your sensitive data in the Secret tab/arduino_secrets.h IPAddress dns(8, 8, 8, 8); // Google DNS int status = WL_IDLE_STATUS; // the WiFi radio's status int ssid_count = 0; // int keyIndex = 0; // your network key Index number (needed only for WEP) uint8_t macaddress[6]; // the MAC address of your Wifi shield UTILE? // ArduinoIoTCloud WiFiConnectionHandler* iot_connector; // incompatibility with EmailSender.h unsigned long timebefore = 0; unsigned long timeSensorRead = 0; bool q2; float volTap1 = 0; float volTap2 = 0; float volTap3 = 0; float volTap4 = 0; float volTap5 = 0; float volTap6 = 0; float volTap7 = 0; float volTap8 = 0; float volTap9 = 0; float volTap10 = 0; float volTap11 = 0; float volTap12 = 0; float volTap13 = 0; float volTap14 = 0; float volTap15 = 0; float pulseTap1 = 0; float pulseTap2 = 0; float pulseTap3 = 0; float pulseTap4 = 0; float pulseTap5 = 0; float pulseTap6 = 0; float pulseTap7 = 0; float pulseTap8 = 0; float pulseTap9 = 0; float pulseTap10 = 0; float pulseTap11 = 0; float pulseTap12 = 0; float pulseTap13 = 0; float pulseTap14 = 0; float pulseTap15 = 0; // NTP time NTPClient timeClient(Udp, "pool.ntp.org", +2 * 3600, 0); // from Arduino Opta - Time zone: GMT+2 // USB Type-A storage USBHostMSD msd; mbed::FATFileSystem usb("usb"); mbed::DigitalOut otg(PB_8, 1); int err; // eMail #define EMAIL_SENDER_DEBUG const char eMailLogin[] = EMAIL_LOGIN; const char eMailPassWord[] = EMAIL_PASSWORD; const char eMailDestinationAdress[] = { TO_EMAIL }; // FlowSensor void SensorFlowTap1Count() { SensorFlowTap1.count(); } // Arduino Giga R1: read whole file from USB-A into a String String readUsbFileToString(const char* path) { String result; FILE* fp = fopen(path, "r"); if (!fp) { Serial.print("Failed to open file: "); Serial.println(path); return ""; } Serial.print("Opened file: "); Serial.println(path); char buffer[256]; while (fgets(buffer, sizeof(buffer), fp)) { result += buffer; } fclose(fp); Serial.print("Read "); Serial.print(result.length()); Serial.println(" bytes from USB file."); return result; } void setup() { Serial.begin(115200); delay(10000); Serial.println("*************************************************"); Serial.println("Arduino Giga R1 WiFi booted."); pinMode(LED_BUILTIN_BLUE, OUTPUT); pinMode(LED_BUILTIN_GREEN, OUTPUT); // USB Type-A storage: mount while (!msd.connect()) { Serial.println("Waiting for an USB Type-A memory stick."); delay(3000); } Serial.println("Mount USB Type-A storage device."); err = usb.mount(&msd); if (err) { Serial.println("Error mounting USB Type-A storage device."); Serial.println(err); while (1) ; } Serial.println("USB Type-A storage mounted."); mbed::fs_file_t file; struct dirent* ent; // WiFi if (WiFi.status() == WL_NO_SHIELD) { // check for the WiFi module Serial.println("Communication with WiFi module failed."); while (true) ; // don't continue } for (byte networkCounter = 0; networkCounter < sizeof(ssid) / sizeof(ssid[0]); networkCounter++) { Serial.println("Attempt to connect to SSID: " + String(ssid[networkCounter])); if (WiFi.begin(ssid[networkCounter], pass[networkCounter]) == WL_CONNECTED) { Serial.print("Connected to "); printWifiStatus(); Serial.print("MAC address: "); WiFi.macAddress(macaddress); Serial.print(macaddress[5], HEX); Serial.print(":"); Serial.print(macaddress[4], HEX); Serial.print(":"); Serial.print(macaddress[3], HEX); Serial.print(":"); Serial.print(macaddress[2], HEX); Serial.print(":"); Serial.print(macaddress[1], HEX); Serial.print(":"); Serial.println(macaddress[0], HEX); break; // connected to network } else Serial.println("NOT CONNECTED to the WiFi router."); } delay(2000); // TEST Serial.println("***** " + getLocaltime()); // ArduinoIoTCloud initProperties(); // This function takes care of connecting your sketch variables to the ArduinoIoTCloud object iot_connector = new WiFiConnectionHandler(ssid[ssid_count], pass[ssid_count]); // xxxx ssid_count ??? // incompatibility with EmailSender.h ArduinoCloud.begin(*iot_connector); ArduinoCloud.addCallback(ArduinoIoTCloudEvent::CONNECT, doThisOnConnect); ArduinoCloud.addCallback(ArduinoIoTCloudEvent::SYNC, doThisOnSync); ArduinoCloud.addCallback(ArduinoIoTCloudEvent::DISCONNECT, doThisOnDisconnect); setDebugMessageLevel(4); // setup debug info ArduinoCloud.printDebugInfo(); // setup debug info // USB Type-A storage: check the CSV file digitalWrite(LED_BUILTIN_BLUE, LOW); // to not unplug the memory storage when the internal LED is ON FILE* dataFile = fopen("/usb/tapslog.csv", "r+"); if (dataFile != NULL) { Serial.println("TapsLog.CSV content:"); char buf[256]; while (fgets(buf, 256, dataFile) != NULL) { // Serial.print(buf); } Serial.println("TapsLog.CSV closing."); fflush(stdout); err = fclose(dataFile); if (err < 0) { Serial.print("fclose error:"); Serial.print(strerror(errno)); Serial.print(" ("); Serial.print(-errno); Serial.print(")"); } else { digitalWrite(LED_BUILTIN_BLUE, HIGH); // to not unplug the memory storage when the internal LED is ON Serial.println("TapsLog.CSV closed."); } } else { Serial.println("TapsLog.CSV doesn't exist. Add column headers."); // USB Type-A storage: add headers to CSV file digitalWrite(LED_BUILTIN_BLUE, LOW); // to not unplug the memory storage when the internal LED is ON FILE* dataFile = fopen("/usb/tapslog.csv", "a"); fflush(stdout); err = fprintf(dataFile, "%s;%s;%s;%s;%s;%s;%s;%s;%s;%s;%s;%s;%s;%s;%s;%s;%s;%s;%s;%s;%s;%s;%s;%s;%s;%s;%s;%s;%s;%s;%s\n", "arraytTime", "arrayVolTap1", "arraypulseTap1", "arrayVolTap2", "arraypulseTap2", "arrayVolTap3", "arraypulseTap3", "arrayVolTap4", "arraypulseTap4", "arrayVolTap5", "arraypulseTap5", "arrayVolTap6", "arraypulseTap6", "arrayVolTap7", "arraypulseTap7", "arrayVolTap8", "arraypulseTap8", "arrayVolTap9", "arraypulseTap9", "arrayVolTap10", "arraypulseTap10", "arrayVolTap11", "arraypulseTap11", "arrayVolTap12", "arraypulseTap12", "arrayVolTap13", "arraypulseTap13", "arrayVolTap14", "arraypulseTap14", "arrayVolTap15", "arraypulseTap15"); if (err < 0) { Serial.println("Fail :("); error("error: %s (%d)\n", strerror(errno), -errno); } Serial.println("TapsLog.CSV closing."); fflush(stdout); err = fclose(dataFile); if (err < 0) { Serial.print("fclose error:"); Serial.print(strerror(errno)); Serial.print(" ("); Serial.print(-errno); Serial.print(")"); } else { digitalWrite(LED_BUILTIN_BLUE, HIGH); // to not unplug the memory storage when the internal LED is ON Serial.println("TapsLog.CSV closed."); } } // FlowSensor Serial.print("Flow sensors mounted: "); SensorFlowTap1.begin(SensorFlowTap1Count); Serial.print("1 "); Serial.println("All flow sensors are mounted."); Serial.println("Waiting for ArduinoCloud connection."); while (!ArduinoCloud.connected()) { ArduinoCloud.update(); // ArduinoIoTCloud } Serial.println("Connected to ArduinoCloud."); Serial.println("Waiting for ArduinoCloud local time."); while (ArduinoCloud.getLocalTime() == int(0)) { ArduinoCloud.update(); // ArduinoIoTCloud } Serial.println("Got ArduinoCloud local time."); * / timeClient.begin(); // NTP client object initialization and time update updateTime(); // Update internal RTC using a NTP server } // end of setup() void loop() { if (millis() - timeSensorRead >= 1000) { SensorFlowTap1.read(); volTap1 = SensorFlowTap1.getVolume(); ArduinoCloud.update(); // ArduinoIoTCloud if (millis() - timebefore >= 60000) { if (ArduinoCloud.connected()) { Serial.println("***** " + getLocaltime()); } // Convert string in char array String stringTime = getLocaltime(); char arraytTime[stringTime.length()]; stringTime.toCharArray(arraytTime, stringTime.length() + 1); if (DEBUG == 1) { Serial.println("=== Sensor 1 :"); //Serial.print("Flow rate (L/mn): "); //Serial.println(flowTap1); //Serial.println(SensorFlowTap1.getFlowRate_m()); Serial.print("Volume (L): "); Serial.println(volTap1); Serial.println(SensorFlowTap1.getPulse()); Serial.println("=== Sensor 2 :"); //Serial.print("Flow rate (L/mn): "); //Serial.println(flowTap2); //Serial.println(SensorFlowTap2.getFlowRate_m()); Serial.print("Volume (L): "); Serial.println(volTap2); Serial.println(SensorFlowTap2.getPulse()); Serial.println("=== Sensor 3 :"); Serial.print("Volume (L): "); Serial.println(volTap3); Serial.println(SensorFlowTap3.getPulse()); Serial.println("=== Sensor 4 :"); Serial.print("Volume (L): "); Serial.println(volTap4); Serial.println(SensorFlowTap4.getPulse()); Serial.println("=== Sensor 5 :"); Serial.print("Volume (L): "); Serial.println(volTap5); Serial.println(SensorFlowTap5.getPulse()); Serial.println("=== Sensor 6 :"); Serial.print("Volume (L): "); Serial.println(volTap6); Serial.println(SensorFlowTap6.getPulse()); } // DEBUG part ArduinoCloud.update(); // ArduinoIoTCloud // USB Type-A storage: handle disconnection and reconnection if (!msd.connected()) { // xxx usful or not as it will reboot anyway? Serial.println("No USB Type-A memory stick present."); msd.connect(); } // USB Type-A storage: write data digitalWrite(LED_BUILTIN_BLUE, LOW); // do not unplug the memory storage when the internal LED is on FILE* dataFile = fopen("/usb/tapslog.csv", "a"); fflush(stdout); err = fprintf(dataFile, "%s;%s;%lu;%s;%lu;%s;%lu;%s;%lu;%s;%lu;%s;%lu;%s;%lu;%s;%lu;%s;%lu;%s;%lu\n", arraytTime, arrayVolTap1, SensorFlowTap1.getPulse(), arrayVolTap2, SensorFlowTap2.getPulse(), arrayVolTap3, SensorFlowTap3.getPulse(), arrayVolTap4, SensorFlowTap4.getPulse(), arrayVolTap5, SensorFlowTap5.getPulse(), arrayVolTap6, SensorFlowTap6.getPulse(), arrayVolTap7, SensorFlowTap7.getPulse(), arrayVolTap8, SensorFlowTap8.getPulse(), arrayVolTap9, SensorFlowTap9.getPulse(), arrayVolTap10, SensorFlowTap10.getPulse(), arrayVolTap11, SensorFlowTap11.getPulse(), arrayVolTap12, SensorFlowTap12.getPulse(), arrayVolTap13, SensorFlowTap13.getPulse(), arrayVolTap14, SensorFlowTap14.getPulse(), arrayVolTap15, SensorFlowTap15.getPulse()); if (err < 0) { Serial.print("Writing failed: "); error("error: %s (%d)\n", strerror(errno), -errno); } fflush(stdout); err = fclose(dataFile); if (err < 0) { Serial.print("fclose error:"); Serial.print(strerror(errno)); Serial.print(" ("); Serial.print(-errno); Serial.print(")"); } else { digitalWrite(LED_BUILTIN_BLUE, HIGH); // do not unplug the memory storage when the internal LED is on Serial.println("TapsLog.CSV closed."); } // Read file from USB Type-A Serial.println("Reading CSV file from USB Type-A"); String csvContent = readUsbFileToString("/usb/tapslog.csv"); if (csvContent.length() == 0) { Serial.println("CSV content is empty or file could not be read. Abort."); return; // stop here; no point in sending an empty attachment } Serial.println("=== CSV CONTENT SAMPLE (first 512 chars) ==="); for (int i = 0; i < (int)csvContent.length() && i < 512; i++) { Serial.print(csvContent[i]); } Serial.println("\n=== END OF SAMPLE ==="); // eMailSender EMailSender emailSend( eMailLogin, eMailPassWord, eMailLogin, "Arduino GIGA", "smtp.gmail.com", 465); // emailSend.setIsSecure(true); // eMailSender: body EMailSender::EMailMessage message; message.subject = "BCB Taproom log"; message.message = "Hello, the beers flow\n" " 18:18 ... :-))"; message.mime = MIME_TEXT_PLAIN; EMailSender::FileDescriptior files[1]; files[0].storageType = EMailSender::EMAIL_STORAGE_TYPE_STRING; files[0].mime = "text/plain"; files[0].filename = "tapslog.csv"; files[0].encode64 = false; // plain text, no need for base64 files[0].content = csvContent; files[0].url = "tapslog.csv"; // dummy path to avoid internal checks EMailSender::Attachments attachs; attachs.number = 1; attachs.fileDescriptor = files; // Send the email EMailSender::Response resp = emailSend.send(eMailDestinationAdress, message, attachs); Serial.println("eMail Sending status:"); Serial.print("resp.code: "); Serial.println(resp.code); Serial.print("resp.desc: "); Serial.println(resp.desc); Serial.print("resp.status: "); Serial.println(resp.status); timebefore = millis(); } // end of timebefore timeSensorRead = millis(); } // end of timeSensorRead } // end of loop() void onQ2Change() { // DIGITAL OUTPUT ON OFF SWITCH if (q2 == true) { digitalWrite(LED_BUILTIN_GREEN, LOW); Serial.println("q2 == true"); } else { digitalWrite(LED_BUILTIN_GREEN, HIGH); Serial.println("q2 == NOT true"); } // Add your code here to act upon Q2 change } // WiFi void printWifiStatus() { // print the SSID of the network you're attached to Serial.print("SSID: "); Serial.println(WiFi.SSID()); // print your board's IP address IPAddress ip = WiFi.localIP(); Serial.print("IP Address: "); Serial.println(ip); // print the received signal strength long rssi = WiFi.RSSI(); Serial.print("Signal strength (RSSI): "); Serial.print(rssi); Serial.println(" dBm."); } void doThisOnConnect() { Serial.println(">>>> CONNECTED Board successfully connected to Arduino IoT Cloud."); } void doThisOnSync() { Serial.println(">>>> SYNC Thing Properties synchronised."); } void doThisOnDisconnect() { Serial.println(">>>> DISCONNECTED Board disconnected from Arduino IoT Cloud."); } // Update internal RTC using a NTP server (from Arduino Opta) void updateTime() { timeClient.update(); const unsigned long epoch = timeClient.getEpochTime(); set_time(epoch); } String getLocaltime() { char buffer[32]; tm t; _rtc_localtime(time(NULL), &t, RTC_FULL_LEAP_YEAR_SUPPORT); strftime(buffer, 32, "%d/%m/%Y %H:%M:%S", &t); return buffer; } void initProperties() { /* ArduinoCloud.setThingId(THING_ID); ArduinoCloud.addProperty(q2, WRITE, ON_CHANGE, onQ2Change); ArduinoCloud.addProperty(volTap1, READ, ON_CHANGE); ArduinoCloud.addProperty(volTap2, READ, ON_CHANGE); ArduinoCloud.addProperty(volTap3, READ, ON_CHANGE); ArduinoCloud.addProperty(volTap4, READ, ON_CHANGE); ArduinoCloud.addProperty(volTap5, READ, ON_CHANGE); ArduinoCloud.addProperty(volTap6, READ, ON_CHANGE); ArduinoCloud.addProperty(volTap7, READ, ON_CHANGE); ArduinoCloud.addProperty(volTap8, READ, ON_CHANGE); ArduinoCloud.addProperty(volTap9, READ, ON_CHANGE); ArduinoCloud.addProperty(volTap10, READ, ON_CHANGE); ArduinoCloud.addProperty(volTap11, READ, ON_CHANGE); ArduinoCloud.addProperty(volTap12, READ, ON_CHANGE); ArduinoCloud.addProperty(volTap13, READ, ON_CHANGE); ArduinoCloud.addProperty(volTap14, READ, ON_CHANGE); ArduinoCloud.addProperty(volTap15, READ, ON_CHANGE); */ }Hello Renzo,
Here is the code used to send successfully a file saved on A USB memory stick.
I will come back later about the ArduinoIoTCloud.
Thank you.
// Read whole file from USB into a String String readUsbFileToString(const char* path) { String result; FILE* fp = fopen(path, "r"); if (!fp) { Serial.print("Failed to open file: "); Serial.println(path); return ""; } Serial.print("Opened file: "); Serial.println(path); char buffer[256]; while (fgets(buffer, sizeof(buffer), fp)) { result += buffer; } fclose(fp); Serial.print("Read "); Serial.print(result.length()); Serial.println(" bytes from USB file."); return result; }// ---- Read CSV file from USB ---- Serial.println("Reading CSV file from USB..."); String csvContent = readUsbFileToString("/usb/tapslog.csv"); if (csvContent.length() == 0) { Serial.println("CSV content is empty or file could not be read. Abort."); return; // stop here; no point in sending an empty attachment } Serial.println("=== CSV CONTENT SAMPLE (first 512 chars) ==="); for (int i = 0; i < (int)csvContent.length() && i < 512; i++) { Serial.print(csvContent[i]); } Serial.println("\n=== END OF SAMPLE ===");// eMailSender EMailSender emailSend( eMailLogin, eMailPassWord, eMailLogin, "Arduino GIGA", "smtp.gmail.com", 465); //emailSend.setIsSecure(true); // eMailSender: body EMailSender::EMailMessage message; message.subject = "BCB Taproom log"; message.message = "Hello, the beers flow\n" " 18:18 ... :-))"; message.mime = MIME_TEXT_PLAIN; EMailSender::FileDescriptior files[1]; files[0].storageType = EMailSender::EMAIL_STORAGE_TYPE_STRING; files[0].mime = "text/plain"; files[0].filename = "tapslog.csv"; files[0].encode64 = false; // plain text, no need for base64 files[0].content = csvContent; files[0].url = "tapslog.csv"; // dummy path, avoids internal checks EMailSender::Attachments attachs; attachs.number = 1; attachs.fileDescriptor = files; // Send the email EMailSender::Response resp = emailSend.send(eMailDestinationAdress, message, attachs); // ok 6/12/25 but no attachement-
This reply was modified 3 days, 13 hours ago by
syrinx.
I probably solve the attachement issue but it remains the issue between Emailsender and ArduinoIoTCloud: the ArduinoIoTCloud needs the arduinobearssl, but it doesn’t work well with emailsender.
-
This reply was modified 1 week ago by
syrinx.
Hello Renzo,
I installed manually the new version 4.1.2 (It’s not available in automatic from the Arduino IDE 2.3.6).
I read a file from the USB A memory stick as recommended by the official documentation for the Giga R1 Wifi: https://docs.arduino.cc/tutorials/giga-r1-wifi/giga-usb/#usb-mass-storage
From your new example for Giga R1 stream reading, I wrote this code:
FILE *dataFile2 = fopen("/usb/tapslog.csv", "r+"); EMailSender::EMailMessage message; message.subject = "BCB Taproom log"; message.message = "Hello, the beers flow 18:18 ... :-))"; message.mime = String(MIME_TEXT_PLAIN); EMailSender::FileDescriptior att; att.mime = String("text/plain"); att.filename = String("tapslog.csv"); att.stream = &dataFile2; emailSend.addAttachment(att);When compiling, I get this error:
“exit status 1
Compilation error: cannot convert ‘FILE** {aka __sFILE**}’ to ‘arduino::Stream*’ in assignment”I believe it’s easy to fix but I tried different modification of the line “att.stream” without any success.
I also tried something like this:
att.stream = &(*((FILE *)dataFile2));The compiling error is:
error: cannot convert ‘FILE* {aka __sFILE*}’ to ‘arduino::Stream*’ in assignment att.stream = &(*((FILE *)dataFile2));According the last Arduino IDE 2.3.6, all my libs are with their last version.
Thank you.
With my Giga, I modified my app to make a stream string.
But when I compile, I get a lot of errors related to bearssl.
Hello Renzo,
I think there is nothing new for the Giga version. Right?
Thank you.
Thanks!
Hello Renzo,
Is it possible to have Gmail with attachements from the USB memory stick in an Arduino Giga?
Thank you.
Thank you. Good luck.
Hello Renzo,
any chance to have Gmail with attachements from the USB memory stick in an Arduino Giga?
Thanks.
Not a good new for this card. I hope you or someone will find a fix.
What type of storage should be used for the USB stick of the Giga? EMAIL_STORAGE_TYPE_FFAT?
Thanks.
Hello Renzo,
Did you succeed with the Giga?
Thanks. Good luck.
Hello Renzo, did you have time to check the feasibility? Thanks.
-
This reply was modified 3 days, 13 hours ago by
-
AuthorPosts
