message:
Arduino MKR wifi 1010 ssl certificate protection

I'm using Arduino IDE v2.1.1 and Arduino MKR wifi 1010. Everything works fine and at this moment I have a need to protect the wifi connection with ssl certificate. I have generated the ssl certificate using the openssl tool and now I have following files that needs to be set in the controller:

 - ca.crt
 - client.crt
 - client.key

how can I set these three files to the MKR wifi 1010 to enable the SSL certificate protected communication? I couldn't find the tutorial or example on the internet.

let me explain how I do that at the moment. I do have a valid self-signed CA certificate and I'm trying to establish a SSL / TLS connection using the CA sertificate only. This is my code which doesn't work unfortunately:

```c++
#include <WiFiNINA.h>
#include <ArduinoJson.h>
#include <ArduinoMqttClient.h>
#include <ArduinoBearSSL.h>
#include <ArduinoECCX08.h>
#include "secrets.h"

char wifiSsid[] = SECRET_WiFi_SSID;
char wifiPass[] = SECRET_WiFi_PASS;
char mqttUserId[] = MQTT_USERID;
char mqttPass[] = MQTT_PASS;
int status = WL_IDLE_STATUS;
const char* rootCAcertificate  = \
"-----BEGIN CERTIFICATE-----\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n" \
"-----END CERTIFICATE-----\n";

bool dev_debug_mode = IS_DEBUG;

WiFiClient    wifiClient;         // Used for the TCP socket connection
BearSSLClient bearSslClient(wifiClient); // Used for SSL/TLS connection, integrates with ECCX08
MqttClient    mqttClient(bearSslClient); // Used for MQTT protocol usage

const char mqttBroker[] = MQTT_BROKER_HOST;
int mqttPort = 8883;

const char deviceRegisterTopic[] = "device/register";

//set interval for sending the Observation (the measurement from the sensor) messages (milliseconds)
const long interval = 3000;

unsigned long previousMillis = 0;

bool deviceIsRegistered = false;

void setup() {
  //Initialize serial and wait for port to open:
  Serial.begin(9600);
  while (dev_debug_mode && !Serial) {
    ; // wait for serial port to connect. Needed for native USB port only - development mode. It has to be removed when releasing to live!!!
  }

  // Check the crypto chip module presence (needed for BearSSL)
  if (!ECCX08.begin()) {
    Serial.println("No ECCX08 present!");
    while (1);
  }

  bearSslClient.setEccSlot(0, rootCAcertificate); // inserting a certificate into the slot 0 (zero)

  // ================ SSL SETUP ================
  // Set a callback to get the current time
  // (used to validate the servers certificate)
  ArduinoBearSSL.onGetTime(getTime);

  // attempt to connect to the Wifi network
  while (status != WL_CONNECTED) {
    Serial.print("Attempting to connect to network: ");
    Serial.println(wifiSsid);
    // Connect to WPA/WPA2 network:
    status = WiFi.begin(wifiSsid, wifiPass);

    Serial.print("Attempt status: ");
    Serial.println(status);

    if(status != WL_CONNECTED) {
      // waiting 10 seconds before trying to connect if it is needed:
      delay(10000);
    }
  }

  // WiFi network connection established! sending some messages to the console
  Serial.println("You're connected to the network");

  Serial.print("Attempting to connect to the MQTT broker: ");
  Serial.println(mqttBroker);
  Serial.println(mqttPort);

  mqttClient.setId(mqttUserId);

  // adding first level of proptection using MQTT broker username and password
  mqttClient.setUsernamePassword(mqttUserId, mqttPass);

  delay(30000);
  while (!mqttClient.connect(mqttBroker, mqttPort)) {
    Serial.print("MQTT connection failed! Error code = ");
    Serial.println(mqttClient.connectError());
    delay(10000);
  }

  // MQTT broker connection established! sending some messages to the console
  Serial.println("You're connected to the MQTT broker!");
  Serial.println();
}

void loop() {

  // call poll() regularly to allow the library to send MQTT keep alive which
  // avoids being disconnected by the broker
  mqttClient.poll();

  // if this current device is not registered yet, registering the device for the first time
  if(!deviceIsRegistered) {
    Serial.print("Sending Device Register message to topic: ");
    Serial.println(deviceRegisterTopic);
    // DO SOMETHING
  }

  unsigned long currentMillis = millis();

  // sending the actual measurement data to the FHIR Server with some time interval, like few seconds. To be defined later.
  if (currentMillis - previousMillis >= interval) {

    // save the last time a message was sent
    previousMillis = currentMillis;

    Serial.println();
  }
}

// ================================== Auxiliary functions ===================================
unsigned long getTime() {
   Serial.print("Current WiFi time:");
   Serial.println(WiFi.getTime());
  // Get the current time from the WiFi module
  return WiFi.getTime();
}
```

in the code above, I'm using the **BearSSLClient** and the certificate is set manually (I prefer this way as it is more transparent for me) `bearSslClient.setEccSlot(0, certificate);` - this is how the certificate is set. Also I do the following call: ArduinoBearSSL.onGetTime(getTime); - to get the proper time. The CA certificate is validated using the **openssl** tool. It is a valid self-signed root certificate.   Please, any help is much appreciated. I'm really confused as it should work since the certificate is a valid self-signed certificate and it is confirmed and verified using the **openssl** tool. When something should work but it doesnt work and I don't have any details except the **-2** error message it makes me feel completely crazy ((((

@b1n3t thank's dude for your help. I appreaciate that. Let me start with one thing, I do software developent for more than 16 years, but I was working with hardware like microcontrollers and i8086 architecture based hardware more than 10 years ago. I was never investigating the SSL /  TLS issues deeply. Now, I go through your questions one by one: yes, I'm sure that Arduino's internal clock is accurate because I have configured myself a mutual TLS connection to the AWS (Amazon) MQTT broker with this clock engaged and everything works fine. The private key might not be properly stored within the ECC608, this might be the issue because I'm not 100% sure that I've done that right. Yes, I have verified that mosquitto MQTT broker's domain and port are accessible from the device, because it connnects successfully without the mutual TLS. I can send message back anf force from the device to the mosquitto MQTT broker server without mutual TLS and without SSL. Yes, I have configured the linux server to enable the 8883 for external connection. I have used the MQTT Explorer tool to establish a mutual TLS connection using the CA root certificate, client and server certificates from another physical device over my LAN network, everything works smoothly, it connects with the CA and client certificate to the MQTT broker server and I can send and receive messages. All is good here. Let me capture the logs and get back. Broker is configured to trust the CA, however all the certificates are self-signed. I have been struggling with this for about five days now and I figured out few important things: the ECC608 is by default (from the factory) in the unlocked state, it can't be used until it is locked (manually from the code). The certificate sign request should be generated on the MRK WiFi 1010 device and the private key is stored internally within the MKR WiFi 1010 device, tha'ts very important detail. Afte that, the CSR should be passed to the certification provider and the sercret certificate should be generated based on that CSR (certificate sign request). Another very important detail is that the self-signed certificate that I'm using for the development might be an issue as it is marked ALWAYS as invalid just because it is self-signed.

**update 22 September**

I'm still struggling with this problem. At this moment, everything is setup and configured on the microcontroller side. The microcontroller can connect to any online test MQTT broker via ssl/tls protocol. I have checked that and double checked. Everything is good on the microcontroller side. My MQTT broker is configured to use TLS v 1.2 it is deployed live, the cetificate is valid, it is generated by the zerossl trusted authority and it just works. I can connect from the test clients to my Mosquitto MQTT broker. I have tried multiple clients and everythig works fine. At this point, I have verified that client is valid and server is valid, both can connect to another party using TLS secure protocol. But, when I'm trying to pair my microcontroller with my Mosquitto MQTT broker - TLS SSL error is thrown, saying that the handshake failed. ssl tls 1.2 error ACCEPT_SR_KEY_EXCH ssl handshake failure. I have tried to debug it using the Wireshark, but there are no details at all. when I try to debug the SSL/TLS using the Wireshark, I see that there is a Client Hello, after that the Server Hello, then Certificate, Server Key Exchange, Server Hello Done and it repeats in a sequence again:

Client Hello, after that the Server Hello, then Certificate, Server Key Exchange, Server Hello Done

Client Hello, after that the Server Hello, then Certificate, Server Key Exchange, Server Hello Done

Client Hello, after that the Server Hello, then Certificate, Server Key Exchange, Server Hello Done

any help is appreciated.

[![enter image description here][1]][1]

  [1]: https://i.stack.imgur.com/JC4oq.png

body:
seems like you have made quite a progress. Frankly, I believe that the problem lies behind not storing your private key in the ECC608.

If the private key is not correctly stored in the ECC608 TLS Handshake will fail. You mentioned the ECC608 is unlocked by default. You're correct that to use the secure functionalities of the chip, it has to be locked. However, as far as I know once it's locked, it can't be unlocked. Make sure you've followed the necessary steps to store your private key in the ECC608 and then locked it to secure the key. I think you can use `ArduinoECCX08` library since it seems to have `ECCX08.begin()`, `ECCX08.lock()`, `ECCX08.generatePrivateKey(slot)` functions. Your approach to generating the CSR directly on the MKR WiFi 1010 device is on point. This method ensures the private key never leaves the device. Consequently, only the public part is sent to the CA, even if it's self-signed. With the CSR, obtain your device certificate. This certificate, coupled with the private key securely housed in the ECC608, should facilitate the TLS handshake.

**TL;DR**: Make sure that you've stored the private key appropriately in the ECC608. Before locking the ECC608, test to ensure that the private key functions as expected. Check your MQTT Broker Logs for further debugging (when provided and when I get time for that I will try my best to pinpoint the error) and try using WireShark to capture SSL traffic.

That is as far as my knowledge goes, all the best luck to you. I hope that I could be of help dude.


sender: user

message:
ESP32 Struggling to Consistently Trigger 4-Channel 5V Relay Module

I'm facing an issue that I can't seem to resolve due to my limited knowledge in electronics. I'm working with a 4-channel 5V relay module and an ESP32 which operates on 3.3V.
[![enter image description here][1]][1]

The setup seemed to work well initially but I have started experiencing some inconsistencies. One of the four relays is working perfectly fine, but the other three are not triggering as they should.

Here are the symptoms:

The LEDs on the non-working relays do light up when a signal is sent from the ESP32, indicating some form of communication.
There is no audible 'click' sound from these relays when they are supposed to trigger.
I noticed that if I gently tap the relay casing, the relay will sometimes trigger, and I can hear it closing.
I had previously thought that I might have fried my first relay module so I replaced it, but the issue reappeared after a few days.

Any guidance would be greatly appreciated as I'm at a loss here. Thank you!

  [1]: https://i.stack.imgur.com/R7RdS.png

sender: assistant

body:
So it turns out that esp32 boards can actually output 5v alongside with 3.3v output pin, You just have to use the VN pin which is used for powering the board when not connected through USB, this is not what the pin is intended for and also might cause some problems and you cannot upload code to the board when VIN pin is connected but so far it works perfectly and outputs consistent 5V that triggers the relays just fine.

Obviously, I was just looking for a solution no matter what risks it imposed, can anyone with a deeper understanding of this topic explain why the power input pin can also work as output and why is this not a feature that comes with esp32 boards


message:
Uploading a Library to the library manager from a Github branch

I am trying to upload a library to the Arduino Library Manager. I know the GitHub - arduino/library-registry: Arduino Library Manager list repository, and I have already read the instructions, but I have a question that I hope someone can explain to me.

The project I am working on is multiplatform, and to fulfill all the requirements for multiple platforms, many files are not required for the Arduino compilation process. I work around this because, with the help of GitHub actions, I have automated a workflow that publishes a branch within the project with an adequate file structure that complies with the Arduino library specification.

On the library-registry repo, step 7 says: " This should be the URL of the repository home page. For example: https://github.com/arduino-libraries/Servo" I am wondering if, in this section, I can put the link to the Arduino branch on the project.

This would mean to include :
https://github.com/myProfileName/myProjectName/tree/Arduino

Instead of :
https://github.com/myProfileName/myProjectName

With the reasoning that the second URL would contain many files that are not needed in an Arduino environment

body:
No. As stated in [the instructions for submitting a library to the Arduino Library Manager registry](https://github.com/arduino/library-registry#instructions), the URL must be to the home page of the repository.

The way [the Library Manager index generation system](https://github.com/arduino/libraries-repository-engine) works:

1. Clone the repository from the URL that was registered URL.
1. Check out each [Git tag](https://git-scm.com/book/en/v2/Git-Basics-Tagging) in the repository.
1. Check to see whether the repository contains an Arduino library at that tag.
1. Check to see whether the library release at that tag is already in the index.
1. If it is a valid new library release, add the release to [the index](http://downloads.arduino.cc/libraries/library_index.json).

So there is no problem with having the Arduino library in a different branches in the repository because the indexer doesn't work from branches. It works from tags, which are independent from branches. You must only make sure to make a Git tag at the commit ref in the Arduino library branch of your repository at the point in the revision history where you make a release of the library.

In case you also want to tag other branches, that is fine. Even though tags are the unit of release for Library Manager, the versioning of the library releases is done exclusively using the value of the `version` field of the [`library.properties` metadata file](https://arduino.github.io/arduino-cli/latest/library-specification/#library-metadata). So you can add something to the tag names to differentiate the Arduino library release tags from tags made in other branches (e.g., `Arduino-1.2.3`, `1.2.3`).

The one consideration with the release strategy I mentioned above is that [the submission validation system](https://github.com/arduino/library-registry-submission-parser) that checks for problems with the library when you [submit](https://github.com/arduino/library-registry#adding-a-library-to-library-manager) it for inclusion in Library Manager checks out [the most recent tag](https://github.com/arduino/library-registry-submission-parser/blob/1.1.1/main.go#L349) in the repository and does that initial validation on the contents of the repository at that specific tag. So you do need to make sure that the Arduino Library release tag is the most recent tag at the time you submit the library.

Once the submission is accepted, all tags in the repository will always be processed (ignoring those that don't pass Arduino Library validation), so it won't matter if tags from branches that don't contain an Arduino library are the most recent tags in the repository after the library has been registered.


message:
SPI with DMA in a Arduino Due

I have a project where I need to store data (~16Mo) on a memory and be able to fetch the data fast (<36000bits/s) with DMA because I have other signals to take care of.

Currently I use a SD card with the SD library but it doesn't seems to use DMA because of the delay between to sending.

Many people told me it shouldn't be that hard and I suppose so. My guess is that I can't configure the DMA and/or the SPI correctly.

I tried something a long time ago : https://arduino.stackexchange.com/questions/92888/send-data-through-spi-with-dma

Can someone show me an example of SPI with DMA, or tips on how to configure both.

Thanks again

body:
```cpp
#include <dmac.h>
#include <SPI.h>
#include <Arduino.h>
#include <sam.h>

uint8_t sourceBuffer[256];

void setup() {
  SPI.begin();
  SPI.setClockDivider(21);  // 4MHz clock (assuming 84MHz system clock)
  setupDMA();
}

void loop() {

  for(int i = 0; i < sizeof(sourceBuffer); i++) {
    sourceBuffer[i] = i;
  }
  startDMATransfer();
  delay(1000);
}

void setupDMA() {
  // Enable the DMA controller
  PMC->PMC_PCER1 |= PMC_PCER1_PID34;  // DMA ID for the Due is 34

  // Disable SPI DMA TX and RX
  SPI0->SPI_PTCR = SPI_PTCR_RXTDIS | SPI_PTCR_TXTDIS;

  // Setup a DMA channel for the transfer (channel 1 for this example)
  DmacChannel* channel = &(DMAC->DMAC_CH_NUM[1]);

  // Disable the DMA channel
  channel->DMAC_CHDR = DMAC_CHDR_DIS;

  // Clear any flags and reset the status
  channel->DMAC_CHDR = DMAC_CHDR_RES;

  // Set up source and destination pointers
  channel->DMAC_SADDR = (uint32_t) sourceBuffer;
  channel->DMAC_DADDR = (uint32_t) &(SPI0->SPI_TDR);

  // Configure source and destination pointers: source increments, destination does not
  channel->DMAC_CTRLA = DMAC_CTRLA_SRC_WIDTH_BYTE | DMAC_CTRLA_DST_WIDTH_BYTE;

  // Set source and destination handshake (related to the SPI0 Tx)
  channel->DMAC_CTRLB = DMAC_CTRLB_SRC_DSCR_FETCH_DISABLE | DMAC_CTRLB_DST_DSCR_FETCH_DISABLE |
                        DMAC_CTRLB_FC_MEM2PER_DMA_FC | DMAC_CTRLB_SRC_INCR_INCREMENTING |
                        DMAC_CTRLB_DST_INCR_FIXED;

  channel->DMAC_CFG = DMAC_CFG_SRC_PER(1) | DMAC_CFG_DST_PER(1) | DMAC_CFG_SOD | DMAC_CFG_FIFOCFG_ALAP_CFG;
}

void startDMATransfer() {
  // Assuming channel 1 is used
  DmacChannel* channel = &(DMAC->DMAC_CH_NUM[1]);

  // Set up the buffer size
  channel->DMAC_CUBC = sizeof(sourceBuffer);

  // Enable SPI DMA for TX
  SPI0->SPI_PTCR = SPI_PTCR_TXTEN;

  // Enable the DMA channel to start the transfer
  channel->DMAC_CHER = DMAC_CHER_ENA;
}
```

When you want to send data via SPI using DMA, you can fill the `sourceBuffer` and call `startDMATransfer()`.

Remember to always refer to the Atmel SAM3X8E datasheet and the Arduino Due's schematic when you are working at this level, as it provides in-depth details on how the hardware functions. I am unable to run the code or test it. But I believe that the code logic is proper. Error handling is up to you.


message:
AccelStepper.h - How can I quickly increase the speed of the NEMA 17 motor?

I'm pretty new to Arduino. I am trying to build a Self-balancing robot. I am using A4988 drivers, ESP32 microcontroller, NEMA 17 motors and a 6050 MPU.

The problem is that, although the speed variable changes according to the position of the MPU. The motors rotate at a slow and constant speed, without varying according to the inclination of the robot.

Here is the code:

```cpp
#include <Adafruit_MPU6050.h>
#include <Adafruit_Sensor.h>
#include <Wire.h>
#include <AccelStepper.h>

#define STEP_IZQ 26
#define DIR_IZQ 27
#define STEP_DER 12
#define DIR_DER 13

AccelStepper stepperizq(AccelStepper::FULL2WIRE,STEP_IZQ,DIR_IZQ);
AccelStepper stepperder(AccelStepper::FULL2WIRE,STEP_DER,DIR_DER);
Adafruit_MPU6050 mpu;

float kp = 20;
float ki = 0.5;
float kd = 30;

float angulo_grad, error,cumError,rateError,output,lastError;
float pid_error_temp, pid_i_mem, pid_setpoint, gyro_input, pid_output, pid_last_d_error;
int speed,outputAbs;

void setup(void) {
  Serial.begin(115200);
  while (!Serial)
    delay(10); // will pause Zero, Leonardo, etc until serial console opens

  Serial.println("Adafruit MPU6050 test!");

  // Try to initialize!
  if (!mpu.begin()) {
    Serial.println("Failed to find MPU6050 chip");
    while (1) {
      delay(10);
    }
  }
  Serial.println("MPU6050 Found!");
  mpu.setAccelerometerRange(MPU6050_RANGE_8_G);
  mpu.setGyroRange(MPU6050_RANGE_500_DEG);
  mpu.setFilterBandwidth(MPU6050_BAND_5_HZ);

  pinMode(DIR_IZQ, OUTPUT);
  pinMode(DIR_DER, OUTPUT);

  stepperizq.setMaxSpeed(3000);
  stepperder.setMaxSpeed(3000);
  stepperizq.setAcceleration(1000); //1000
  stepperder.setAcceleration(1000); //1000
}

void loop() {
  /* Get new sensor events with the readings */
  sensors_event_t a, g, temp;
  mpu.getEvent(&a, &g, &temp);

  angulo_grad = atan((a.acceleration.x)/(a.acceleration.z))*(180/3.14);            //0 to 90 degrees
  //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  // pid
  /////////////////////////////////////////////////////////////////////////////////////////////////

  pid_error_temp = angulo_grad;
  if((pid_error_temp > -2.0 )&&( pid_error_temp < 2.0)) pid_error_temp = 0.0;

  pid_i_mem += ki * pid_error_temp;                                 //Calculate the I-controller value and add it to the pid_i_mem variable
  if(pid_i_mem > 800)pid_i_mem = 800;                                       //Limit the I-controller to the maximum controller output
  else if(pid_i_mem < -800)pid_i_mem = -800;
  //Calculate the PID output value
  pid_output = kp * pid_error_temp + pid_i_mem + kd * (pid_error_temp - pid_last_d_error);
  if(pid_output > 5000)pid_output = 5000;                                     //Limit the PI-controller to the maximum controller output
  else if(pid_output < -5000)pid_output = -5000;

  if(output < 50 && output > 50)output = 0;
  pid_last_d_error = pid_error_temp;
  ////////////////////////////////////////////////////////////////////////////////////////////////////
  //motors nema 17
  //////////////////////////////////////////////////////////////////////////////////////////////////////////////
  outputAbs = (int)abs(pid_output);
  speed = map(outputAbs,0,5000,0,3000);

  stepperizq.setSpeed(speed);
  stepperder.setSpeed(speed);

  if(pid_output<0){
    digitalWrite(DIR_IZQ,LOW);
    digitalWrite(DIR_DER,HIGH);
  }
  else if(pid_output>0){
    digitalWrite(DIR_IZQ,HIGH);
    digitalWrite(DIR_DER,LOW);
  }
  stepperizq.runSpeed();
  stepperder.runSpeed();
}
```

body:
To write down my guess from the comments in a proper answer:

When a stepper motor driven with AccelStepper shows a constant speed, though the speed is set to different values, it suggests, that the time interval of the steps is defined by something else.

The `runSpeed()` function works by saving a timestamp of the last step and then checking the elapsed time on the basis of the set speed, to check if the time for another step has come and if yes, then execute exactly one step. For this to work correctly, you need to call this function within intervals smaller than the smallest period between two consecutive steps for your speed.

If for whatever reason you call the function with larger intervals, the `runSpeed()` function will always see, that the time for a new step has come, but it will always only do one step per execution. Thus you overall get one step per `runSpeed()` execution, and this is determined by the rest of your code, not the set speed.

The rest of the code in `loop()` is for getting the measurements of the MPU and calculating the resulting speeds from that. Probably this is taking too long and thus hindering the AccelStepper library from running the motor at the specified speeds. So you need to provide a larger timeslot for the stepper driving on your ESP by cutting down on your MPU sampling rate. This is easiest done by using

    // Running MPU sampling and calculation only every 100ms
    if(millis() - previousMillis >= 100){
      previousMillis += 100;
      // MPU and calculation code here
    }
    // Running the stepper code on every loop iteration
    stepperizq.runSpeed();
    stepperder.runSpeed();

which is the non-blocking coding style used in the `BlinkWithoutDelay` example. If you don't know how to use `millis()`, there are many tutorials online for that.


message:
IR Remote control on UNO

I am working on IR remote code run on Arduino UNO
I can already get it work. but when I press the button and hold, the output is sent with the same value repeatly. So,the quesion is how can I do to make it send out only one output while I press and hold the button.

this is my code
```
#include <IRremote.h>
int RECV_PIN = 5;
#define PB  3392264773 // button code
#define VUP  3476004267 // button code
#define VDN  2998643817 // button code
#define SRC  387001607 // button code
#define MUTE  305976139 // button code

IRrecv irrecv(RECV_PIN);
decode_results results;
void setup()
{
  Serial.begin(9600);
  irrecv.enableIRIn(); // Start the receiver
}
void loop() {
  if (irrecv.decode(&results)) {

    if (results.value == PB) {
      Serial.println("Power");
    }
    if (results.value == VUP) {
      Serial.println("Vol UP");
    }
    if (results.value == VDN) {
      Serial.println("Vol Down");
    }
    if (results.value == SRC) {
      Serial.println("Select");
    }
    if (results.value == MUTE) {
      Serial.println("Mute");
    }

    irrecv.resume(); // Receive the next value

  }
}
```
and this is output when I press and hold the button
```
Power
Power
Power
Power
Power
Vol UP
Vol UP
Vol UP
Vol UP
Vol UP
Vol UP
Vol UP
Vol UP
```
Thank you for all answers.
Tanwa

body:
As noted in the comments, you cannot change what the remote is sending. Though I guess, that it would be OK for you to just react to the first occurence of a specific value send consecutively. For that you first need to check the time between these consecutive values send, when holding the button down. That (plus a small margin) will be the threshold to recognize multiple distinct button presses. Note: Depending on the rate, that the remote is sending when holding a button, this might mean, that you cannot distinguish between holding a button and pressing it multiple times in a fast pace.

First define a variable to hold the previous decode results and a timestamp for saving when it arrived:

    decode_results previous_results;
    unsigned long previous_timestamp;

On receiving a new value via IR, check if the new value is the same as in `previous_results`. If yes, don't execute the code checking for the actual value. If no, then update `previous_results` with the new value and act upon the actual received value. Then set the timestamp to the current `millis()` value and resume receiving.

    if (irrecv.decode(&results)) {
      if(results != previous_results){
        previous_results = results;
        if (results.value == PB) {
          Serial.println("Power");
        }
        ....
      }
      previous_timestamp = millis();
      irrecv.resume(); // Receive the next value
    }

Now you need to reset the `previous_results` variable after a specific time threshold, so that consecutive presses on the same button can be registered. Add a corresponding `millis()` statement to your `loop()` function:

    if(millis() - previous_timestamp > 500){
      previous_results = 0;
    }

Note: The value of 500ms is just a wild guess. As described at the start, you need to find that value yourself, fitting to your remote. Play a bit with this value until you are satisfied.

All in all something like this:

    #include <IRremote.h>
    int RECV_PIN = 5;
    #define PB  3392264773 // button code
    #define VUP  3476004267 // button code
    #define VDN  2998643817 // button code
    #define SRC  387001607 // button code
    #define MUTE  305976139 // button code

    IRrecv irrecv(RECV_PIN);
    decode_results results;
    decode_results previous_results;
    unsigned long previous_timestamp;

    void setup()
    {
      Serial.begin(9600);
      irrecv.enableIRIn(); // Start the receiver
    }
    void loop() {
      if (irrecv.decode(&results)) {
        if(results != previous_results){
          previous_results = results;
          if (results.value == PB) {
            Serial.println("Power");
          }
          if (results.value == VUP) {
            Serial.println("Vol UP");
          }
          if (results.value == VDN) {
            Serial.println("Vol Down");
          }
          if (results.value == SRC) {
            Serial.println("Select");
          }
          if (results.value == MUTE) {
            Serial.println("Mute");
          }
        }
        previous_timestamp = millis();
        irrecv.resume(); // Receive the next value
      }

      if(millis() - previous_timestamp > 500){
        previous_results = 0;
      }
    }

Note: I have not tested this code in any way.


body:
by adapting chrisl's idea, I got it done. the code is here.
```
#include <IRremote.h>
int RECV_PIN = 5;
#define PB  3392264773 // button code
#define VUP  3476004267 // button code
#define VDN  2998643817 // button code
#define SRC  387001607 // button code
#define MUTE  305976139 // button code

int pre_p  = 0;
int pre_src  = 0;
int pre_mu  = 0;

//trigger
int p = 0;
int src = 0;
int mu = 0;

int pw = 0;
int s = 0;
int m = 0;

IRrecv irrecv(RECV_PIN);
decode_results results;

unsigned long previous_timestamp;
unsigned long check_timestamp;

void setup()
{
  Serial.begin(9600);
  irrecv.enableIRIn(); // Start the receiver
}
void loop() {
  if (irrecv.decode(&results)) {

        if (results.value == PB){
           p = 1;
          if(p != pre_p){
           pw = !pw;
            //Serial.println(pw);
              Serial.println("pw");
              Serial.println(pw);
          }
        }
      if (results.value == VUP) {
        Serial.println("Vol UP");
      }
      if (results.value == VDN) {
        Serial.println("Vol Down");
      }
      if (results.value == SRC) {
        src = 1;
          if(src != pre_src){
           s = !s;
          Serial.println("s");
          Serial.println(s);
          //Serial.println("Select");
          }
      }
      if (results.value == MUTE) {
        mu = 1;
          if(mu != pre_mu){
           m = !m;
          //Serial.println("Mute");
          Serial.println("mu");
          Serial.println(m);
          }
      }

    irrecv.resume(); // Receive the next value
    pre_p = p;
    pre_src  = src;
    pre_mu  = mu;

    p=0;
    src = 0;
    mu = 0;

    previous_timestamp = millis();

  }
    if(millis() - previous_timestamp > 200){
    pre_p = 0;
    pre_src  = 0;
    pre_mu  = 0;
  }
}
```


message:
Sparkfun Pro Micro (5v) as ISP error

I'm trying to use Sparkfun Pro Micro (5v 16MHz) as ISP to program Attiny chips (OS:Windows10Pro). I followed instructions. Installed proper driver and added Sparkfun boards to ArduinoIDE:

[![enter image description here][1]][1]

Using Arduino IDE uploaded ArduinoISP sketch on it. As you can see there are two options available to choose for programmer:

 1. Arduino as ISP
 2. Arduino Leonardo/Pro Micro as ISP

[![enter image description here][2]][2]

Which unfortunately both of them give the same error:

    Sketch uses 28 bytes (2%) of program storage space. Maximum is 1024 bytes.
    Global variables use 0 bytes (0%) of dynamic memory, leaving 64 bytes for local variables. Maximum is 64 bytes.
    C:\Users\K1\AppData\Local\Arduino15\packages\MicroCore\tools\avrdude\7.1-arduino.1/bin/avrdude -CC:\Users\K1\AppData\Local\Arduino15\packages\MicroCore\hardware\avr\2.3.0/avrdude.conf -v -pattiny13a -cstk500v1 -PCOM16 -b19200 -Uhfuse:w:0xff:m -Ulfuse:w:0b00111010:m -Uflash:w:C:\Users\K1\AppData\Local\Temp\arduino_build_207900/sketch_aug28a.ino.hex:i

    avrdude: Version 7.2
    Copyright the AVRDUDE authors;
    see https://github.com/avrdudes/avrdude/blob/main/AUTHORS

    System wide configuration file is C:\Users\K1\AppData\Local\Arduino15\packages\MicroCore\hardware\avr\2.3.0\avrdude.conf

    Using Port                    : COM16
    Using Programmer              : stk500v1
    Overriding Baud Rate          : 19200
    avrdude stk500_recv() error: programmer is not responding
    avrdude stk500_getsync() warning: attempt 1 of 10: not in sync: resp=0x00
    avrdude stk500_recv() error: programmer is not responding
    avrdude stk500_getsync() warning: attempt 2 of 10: not in sync: resp=0x00
    ...

    avrdude done.  Thank you.
    the selected serial port
     does not exist or your board is not connected

I tried avrdude in command line with these parameters and got the same results:

    avrdude -p attiny13a -P COM16 -c avrisp -b 19200 -U flash:w:r.hex -v

I also found out that issue most probably has nothing to do with:

 - Target chip that I'm using: because changing it has no effect
 - Wiring: because even when there is no chip connected to SPI pins of ProMicro I get the same error
 - USB cable is good: I can upload sketches successfully to Pro Micro but cannot use it as ISP and replaced cable to rule that probably out.

This is while in this video the guy does what I want easily and has no issues whatsoever:
[https://www.youtube.com/watch?v=7Rz9A9VbDx4][3]

Any ideas appreciated.

  [1]: https://i.stack.imgur.com/1eUd1.png
  [2]: https://i.stack.imgur.com/dIhPo.png
  [3]: https://www.youtube.com/watch?v=7Rz9A9VbDx4

body:
GOTCHA...
After two days of search and speculation finally found the solution:

**Short answer:**
In avrdude command instead of **-c avrisp** use **-c arduino**:

    avrdude -p attiny13a -P COM16 -c arduino -b 19200 -U flash:w:r.hex -v

**Long answer:**
My target chip was ATtiny13a, so I had to use MicroCore v2.3.0 which is the only core supporting ATtiny13 for Arduino. Contrary to other cores, in this core's programmers.txt list, each entry should have a *upload.protocol* line:

    arduinoasispatmega32u4.upload.protocol=

otherwise it will give this error:

    avrdude programmer_not_found() error: cannot find programmer id {upload.protocol}

I have added this line before to make that error go away but apparently with wrong parameter of **stk500v1** that I have imitated from fabric entries! Converting this parameter to **arduino** solved the problem. This is what that entry should look like for ATtiny13 of MicroCore v2.3.0 (\packages\MicroCore\hardware\avr\2.3.0\programmers.txt):

    arduinoasispatmega32u4.name=Arduino Leo/Micro as ISP
    arduinoasispatmega32u4.communication=serial
    arduinoasispatmega32u4.protocol=arduino
    arduinoasispatmega32u4.upload.protocol=arduino
    arduinoasispatmega32u4.speed=19200
    arduinoasispatmega32u4.program.protocol=arduino
    arduinoasispatmega32u4.program.speed=19200
    arduinoasispatmega32u4.program.tool=avrdude
    arduinoasispatmega32u4.program.extra_params=-P{serial.port} -b{program.speed}

For other cores, like ATTinyCore v1.5.2 (\packages\ATTinyCore\hardware\avr\1.5.2\programmers.txt) no such line is needed hence this entry works fine:

    arduinoasispatmega32u4.name=Arduino Leo/Micro as ISP
    arduinoasispatmega32u4.communication=serial
    arduinoasispatmega32u4.protocol=arduino
    arduinoasispatmega32u4.speed=19200
    arduinoasispatmega32u4.program.protocol=arduino
    arduinoasispatmega32u4.program.speed=19200
    arduinoasispatmega32u4.program.tool=avrdude
    arduinoasispatmega32u4.program.extra_params=-P{serial.port} -b{program.speed}

Also you should update avrdude in the Arduino core manually:
Download latest release from [HERE][1], and replace them IDE's related files. If you can not find them take a look at [HERE][2]. If avrdude is not updated you might get an error like this:

    Error during upload using programmer
    The uploader process failed

    The uploader process failed
    The uploader returned an error
    avrdude: Version 6.3-20201216
             Copyright (c) 2000-2005 Brian Dean, http://www.bdmicro.com/
             Copyright (c) 2007-2014 Joerg Wunsch
             System wide configuration file is "C:\Users\K1\AppData\Local\arduino15\packages\MicroCore\hardware\avr\2.3.0/avrdude.conf"
    avrdude: error at C:\Users\K1\AppData\Local\arduino15\packages\MicroCore\hardware\avr\2.3.0/avrdude.conf:421: syntax error
    avrdude: error reading system wide configuration file "C:\Users\K1\AppData\Local\arduino15\packages\MicroCore\hardware\avr\2.3.0/avrdude.conf"

**Third Solusion:**
Use this App with this configuration:
[![enter image description here][3]][3]

  [1]: https://github.com/avrdudes/avrdude/releases
  [2]: https://forum.arduino.cc/t/avrdude-install-location/532406
  [3]: https://i.stack.imgur.com/9ZyDM.png


message:
ESP32 TTGO T-Call connect to SX1276

I have an [ESP32 TTGO T-Call][1] and I want to add a LoRa SX1276. I am new to that and I am trying to write a simple program that, when it receives a packet from a LoRa sender, sends via gsm an HTTP request. GSM communication works fine with the TinyGSM library. My problem is the LoRa connection.

Specific chips according to [this issue][2] have some reserved pins. If I use the pins of [the above example][3] lora works but GSM does not work, because of the reserved pins for the SIM800. I am posting a piece of code with the LoRa setup that is not working. If there is a need for further explanation please ask. I will appreciate any kind of help.
```c++
#define SCK 14
#define SS 15
#define MISO 19
#define MOSI 27
#define RST 34
#define DIO0 33

SPI.begin(SCK, MISO, MOSI, SS);
//setup LoRa transceiver module
LoRa.setPins(SS, RST, DIO0);

while (!LoRa.begin(866E6)) {
    SerialMonitor.println(".");
    delay(500);
}
SerialMonitor.println("LoRa Initializing OK!");
```

**Edited**

With setting

```c
#define LORA_MISO 19
#define LORA_MOSI 27
#define LORA_SCK 5
#define LORA_SS 18

#define LORA_RST 14
#define LORA_DIO0 26
```

Lora works (not sim800) but with the settings of @Juraj comment i am getting

> E (11571) gpio: GPIO can only be used as input mode
> [ 11575][E][esp32-hal-gpio.c:130] __pinMode(): GPIO config failed
> E (11571) gpio: gpio_set_level(226): GPIO output gpio_num error
> E (11586) gpio: gpio_set_level(226): GPIO output gpio_num error

**Edit**

Although the error exists it is working with the above settings:

```c
#define LORA_MISO 2
#define LORA_MOSI 13
#define LORA_SCK 14
#define LORA_SS 15

#define LORA_RST 34
#define LORA_DIO0 25
```

Some packets from the sender are lost but it seems to be working. I don't know why, but it is working... Also it does not seem very stable.

Finally pins 34-39 can be used as input so `#define LORA_RST 34` is not working. But it is not receiving yet from the sender.

  [1]: https://www.lilygo.cc/products/t-call-v1-4
  [2]: https://github.com/Xinyuan-LilyGO/LilyGo-T-Call-SIM800/issues/49
  [3]: https://randomnerdtutorials.com/ttgo-lora32-sx1276-arduino-ide/

body:
The issue seems to be arising from the pin definitions and the fact that the SIM800 and the SX1276 LoRa chip on the board might be competing for the same pins, causing interference

First, let's understand the TTGO T-Call pin mapping for SIM800:

SIM800L IP5306 version 20190610:

 1. **4: SIM800L RST**
 2. **23: SIM800L DTR**
 3. **26: SIM800L PWR**
 4. **27: SIM800L TX**
 5. **32: SIM800L RX**
 6. **33: SIM800L RI**

From the pins you've listed for the LoRa SX1276:

 1. **SCK: 14**
 2. **SS: 15**
 3. **MISO: 19**
 4. **MOSI: 27**
 5. **RST: 34**
 6. **DIO0: 33**

It's clear that MOSI on 27 and DIO0 on 33 interfere with SIM800L's pins.

You need to select pins for LoRa that do not interfere with the SIM800L. However, **keep in mind that the ESP32 has certain pins that are not suitable for all types of connections.**

a proposed remapping would be as follows:

    #define SCK 14
    #define SS 15
    #define MISO 19
    #define MOSI 22
    #define RST 34
    #define DIO0 25

Tell me if this works.


message:
Weird Behaviour with BearSSL on GPIO ESP8266

I use GPIO 5 to trigger a relay, my code also connects with a secure MQTT connection for which I have to use the BearSSL certificate definitions.
Without the BearSSL certificates, when the esp restarts it does not re-trigger the relay, and the GPIO maintains its state between reboots, but when I use the bearSSL certificates the behavior changes, and GPIO 5 goes low on restart. Any explanation why and how to mitigate it?

I am 100% sure it is because of the import, cause I removed components of my code until I could find the piece of code that caused this, and it was because of the declarations.
```c++
    #include <WiFiClientSecure.h>
    static const char AWS_CERT_CA[] PROGMEM = R"EOF(
    aws root)EOF";

    static const char AWS_CERT_CRT[] PROGMEM = R"KEY(
    device cert)KEY";

    static const char AWS_CERT_KEY[] PROGMEM = R"KEY(
    device key )KEY";

    BearSSL::X509List cert(AWS_CERT_CA);
    BearSSL::X509List client_crt(AWS_CERT_CRT);
    BearSSL::PrivateKey key(AWS_CERT_KEY);

    WiFiClientSecure espClient;
    void setup() {
      pinMode(5, OUTPUT);
      delay(2000);
      digitalWrite(5, HIGH);
      delay(2000);
      ESP.restart();
     }

    void loop() {}
```
Without the following three lines
```c++
    BearSSL::X509List cert(AWS_CERT_CA);
    BearSSL::X509List client_crt(AWS_CERT_CRT);
    BearSSL::PrivateKey key(AWS_CERT_KEY);
```
The LED on GPIO 5 does not flicker on restarts but adding these lines makes them flicker. Any solution or suggestion towards a solution for this problem will be really helpful.

body:
What worked for me was to move the BearSSL declaration and usage after the pinMode setting of the GPIO. So I had to make the certificate and keys local variables and wrap the entire setting up of wifi, conneting to it, setting up and connecting to the AWS core in a single function.

    void setupWiFiAndConnectAWS() {
      BearSSL::X509List cert(AWS_CERT_CA);
      BearSSL::X509List client_crt(AWS_CERT_CRT);
      BearSSL::PrivateKey key(AWS_CERT_KEY);
      WiFi.persistent(false);
      DEBUG_MSG("[setupWiFi] Setting host name\n");
      WiFi.hostname(deviceId);
      DEBUG_MSG("[setupWiFi] Setting station mode\n");
      WiFi.mode(WIFI_STA);
      if (WiFi.getMode() & WIFI_AP) {
        WiFi.softAPdisconnect(true);
      }
      WiFi.persistent(false);
      DEBUG_MSG("[setupWiFi] Loading certificates\n");
      net.setTrustAnchors(&cert);
      net.setClientRSACert(&client_crt, &key);
      loadCredentials();
      connectWiFi();
      attachInputInterrupts(false);
      setupNTP();
      connectAWS();
    }

after setting up the GPIO pins.
Although this is a work around, I still don't understand the core problem and would like to understand it


message:
Why Arduino IDE is brignging wrong board name for ESP32 S3

[![enter image description here][1]][1]

I am designing a pcb for ESP32 S3 wroom-1 for testing pins which are safe to use.

My PCB look like this:

[![enter image description here][2]][2]

 I program ESP32 S3 via USB interface gpio19 "D-" gpio20 "D+". When I plug in my usb, Arduino ide brings wrong name for my Esp32 board. By the way I use USB TYPE C. Everyday it gives different names. Correct one is "ESP32S3 DEV MODULE".

**How can I set it to select the correct module automatically on Arduino Ide** as ESP32S3 Dev Module?

WRONG 1

[![enter image description here][3]][3]

WRONG 2

[![enter image description here][4]][4]

WRONG 3

[![enter image description here][5]][5]

same board different names. interesting

  [1]: https://i.stack.imgur.com/FaqN7.png
  [2]: https://i.stack.imgur.com/6zZV9.png
  [3]: https://i.stack.imgur.com/V78nw.png
  [4]: https://i.stack.imgur.com/YtPrf.png
  [5]: https://i.stack.imgur.com/Gu5kB.png

body:
You can just force Arduino IDE to recognise your board by locating your *Boards Configuration File*, putting in your VID and PID values, repackage and host the configurations and Point the Arduino IDE to your custom board manager URL.

On my MacBook device I have used `ioreg -p IOUSB -l` after plugging in a device and copy the idVendor, idProduct properties. These are the VID and PID values. On Windows you may open Device Manager, look under the Ports (COM & LPT), right click on your board (it might appear as a COM port) and choose "properties", go to "details" menu, and there from the dropdown menu, select "Hardware Ids". you should see values like VID_XXXX&PID_YYYY. these are your VID and PID. on Linux you may just use "lsusb" and find the vendor ID and PID there.

After finding those you must go to ESP32 board package directory and find boards.txt (https://github.com/espressif/arduino-esp32/blob/master/boards.txt). Find the line that starts with `esp32s3.name=ESP32S3 Dev Module`. There you must modify the PID and VID values with your actual VID and PID values that you collected as mentioned above. Replace `0xXXXX` with your VID and `0xYYYY` with your PID.

After modifying, you'll need to compress the entire board package directory into a ZIP archive. Make sure the directory structure remains intact so that the Arduino IDE can recognize and install it correctly.

Then you can create a new repository on GitHub, upload the ZIP archive to this repository, then click on the ZIP file inside the repository, then click the "Download" button. Copy the link.

Now you must go to the Arduino IDE, go to `file` -> `preferences`. in the "Additional Boards Manager URLs" field, click on the icon on the right to open a window where you can insert new lines. Add the direct link to your ZIP file and click OK. Go to Tools -> Board -> Boards Manager. then search for ESP32. your custom package should appear in the list. Click "Install". after it installs you are good to go.

**VERY IMPORTANT EDIT**: after investigating this issue a little more I have came to realisation that so called "random board names" that show up all have the same VID and PID values. The problem was not the incorrect VID and PID values for your board, **the problem was that a bunch of other boards also have the same VID and PID values**. A simple yet effective fix would be to assign random names to all the other ones than the one you want to use. Just edit the

    adafruit_qtpy_esp32c3.vid.0=0x303a

    adafruit_qtpy_esp32c3.pid.0=0x1001

lines for every board other than what you want to use. But never forget to change this text file if you ever start doing long-run development with one of the other boards. Or the other boards (such as u-blox NORA-W10 s3" won't be auto detected.


body:
After an Arduino IDE update 2.2, something was solved, yesterday (30,08,2023).

There is a new edit button appearing on the board selection menu and then Arduino ide recognises esp32 even after plugging out and in again.

[![enter image description here][1]][1]

  [1]: https://i.stack.imgur.com/eTPhX.png


message:
Multiple TFT's not displaying

I am trying to connect about 5 TFT's to my Arduino Uno and I got to the point of hooking two of them up without any issues. However, after a code upload, they stopped working. I then took all the code out and tested each in isolation and they still function. However, together only one of them displays data.
The TFT's I am using are the ST7789v2 found here. https://www.waveshare.com/wiki/1.69inch_LCD_Module#Hardware_Connection_3

I have wired them up according to the schematic with "all" pins being shared except the CS pin. Each display has its own.

The code looks like this;

    #include <Adafruit_GFX.h>
    #include <Adafruit_ST7789.h>

    #define TFT_CS1 10
    #define TFT_CS2 3

    #define TFT_RST        8 // Screens shared
    #define TFT_DC         7 // Screens shared
    #define TFT_BACKLIGHT  9 // Backlight for all screens

    Adafruit_ST7789 tftHour1 = Adafruit_ST7789(TFT_CS1, TFT_DC, TFT_RST);
    Adafruit_ST7789 tftHour2 = Adafruit_ST7789(TFT_CS2, TFT_DC, TFT_RST);

    Adafruit_ST7789 setupScreen (Adafruit_ST7789 tft){
      tft.init(240, 280);
      tft.fillScreen(ST77XX_BLACK);
      return tft;
    }

    void setup(void) {
      tftHour1 = setupScreen(tftHour1);
      tftHour2 = setupScreen(tftHour2);
    }

    void loop(){
      tftHour1.print("1");
      tftHour2.print("2");
    }

When this executes, display 2 shows output but display 1 does not. Weirdly if I take the CS from display 1 and pop it into the same line on the breadboard as CS2, and then put it back into its original position, display 1 and 2 seem to work. But only till the next power cycle or upload.

Also oddly, setting the colour of each screen works even if one is blue and the other is say green. Both change to their respective colours. But when I try to write text to them, only one of them has text.

If I comment the code for tftHour2, then tftHour1 starts showing text. If I swap the setup code for ftfHour1 and tftHour2, then the display that is last to init, is the one that shows the text and the other stays blank.

Like I said, I had all this working and then a simple font change upload and it all stopped working.

Any help on this is really appreciated.

I should mention that I am a programmer and very new to electronics so please keep it simple.

#**Update**. If I have separate RST pins then it works. But I need 5 screen and will run out of pins in that case. Is there a way to get around that?

body:
According to the data sheet, the RST signal is accepted without an active CS, so when sharing this signal, **all** displays are reset if you initialize just one of them. That explains the behavior you observe.

You found the solution: Do not share the RST signal in all instances of `Adafruit_ST7789`.

---

Now you worry about the needed number of pins, and that is indeed an issue.

One possible solution is to use a decoder that takes _n_ inputs to activate 1 of 2n outputs, like this:

![schematic](http://i.stack.imgur.com/5lubu.png)

To control 5 RST lines you will need only 3 pins. Use a binary value to select one of the unused outputs to deactivate all RST lines.

The same is true of the CS lines.

However, the library in use does not support this kind of control. Therefore, I'm afraid that you need to consider another Arduino model with more pins.

---

As a work-around, you might want to try this alternative:

Assign the same Arduino pin to all instances of `Adafruit_ST7789`, as in your first attempt. But do not connect it to the RST inputs of the displays. Leave the Arduino pin unconnected.

Instead, use another Arduino pin and connect that to the displays. Then during initialization, reset all displays with your own code. See the data sheet for correct levels and timing.

Or try to connect the RST inputs of all displays to VCC, as they may work without an explicit hardware reset just fine.

---

In a comment you brought up the idea of using a multiplexer.

Without any other change, you would need the selection signals as additional pins to the multiple CS pins, in your case 3 more.

Instead you can also share the CS signal in the same way:

![schematic](http://i.stack.imgur.com/CkiYH.png)

It is very important that you use multiplexers that output the inactive level as required by the displays on not selected outputs!

Even now you should instantiate as many `Adafruit_ST7789` as you have displays, because each instance most probably stores internal information necessary for its correct working. But you can use the same pins on all of them.

Before you call any method of an instance, switch the multiplexers to the associated display.

To be sure that all data is completely transmitted, you might need a small delay after the called method. Perhaps the called method already blocks until all data is completely transmitted. You might try to read the library's source to learn more.


message:
Using Internal Timer Interrupt to Read Analog Sensor

I'm having difficultly using an internal timer interrupt with my Arduino Nano to properly capture a specific value from a linear potentiometer and then instantly stopping the actuator.

I basically have the wiper of a linear potentiometer connected to the end of a linear actuator.  The actuator extends/retracts via a L298N module being controlled by a Nano.  From where its positioned, the potentiometer reads around "80" when the actuator is fully extended, and around "25" when fully retracted.  I'm entering numbers via the serial monitor to prompt the actuator to move up or down, these numbers are being stored in the Nano's EEPROM.

My interrupt seems not to work while the actuator is in motion.  For example, if I set the interrupt to stop the motor when the potentiometer reads "50", it just skips past this number without stopping the actuator.  But if I set the interrupt to stop the motor when the potentiometer reads the minimum or maximum (where the actuator is currently located before activation), the actuator correctly doesn't extract or retract.  I would think my interrupt is fast enough at 8Khz, so I feel there is something else prohibiting the actuator from stopping at a specific value between the max and min.

The my current code is below, any help would be much appreciated.
```c++
    //timer2 will interrupt at 8kHz

    #include <EEPROM.h>
    #define EEPROM_SIZE

    long number;
    long x;

    int toggle=0;
    int old_x=0;

    const int linPot = A1;

    int MotorSpeed=255;

    int enA = 9;
    int in1 = 8;
    int in2 = 7;

    int currentPosition;

    enum {IdleState, UpState, DownState} State;

    void setup(){

      Serial.begin(9600);

      number = EEPROM.read(0);

      x=number;

      pinMode(enA, OUTPUT);
      pinMode(in1, OUTPUT);
      pinMode(in2, OUTPUT);

      State = IdleState;

    //cli();//stop interrupts

    //set timer2 interrupt at 8kHz
      TCCR2A = 0;// set entire TCCR2A register to 0
      TCCR2B = 0;// same for TCCR2B
      TCNT2  = 0;//initialize counter value to 0
      // set compare match register for 8khz increments
      OCR2A = 249;// = (16*10^6) / (8000*8) - 1 (must be <256)
      // turn on CTC mode
      TCCR2A |= (1 << WGM21);
      // Set CS21 bit for 8 prescaler
      TCCR2B |= (1 << CS21);
      // enable timer compare interrupt
      TIMSK2 |= (1 << OCIE2A);

    sei();//allow interrupts

    }//end setup

    ISR(TIMER2_COMPA_vect){//timer1 interrupt 8kHz
    //generates pulse wave of frequency 8kHz/2 = 4kHz

    if(currentPosition==50){

      HALT();

    }

    }

    void loop(){

    if ((Serial.available()&&toggle==0)){

            x=Serial.parseInt();
            old_x=x;
            toggle=1;
          }

          if((Serial.available())&&(toggle==1)&&(Serial.parseInt()!=old_x)){
              toggle=0;
          }

            if((toggle==1)&&(Serial.parseInt()==0)){
              toggle=0;
          }

          if(x>78){
            x=78;
          }

           if(x<0){
            x=0;
          }

        EEPROM.write(0, x);
        Serial.print("X :");
        Serial.println(x);

        int data = analogRead(linPot);
        currentPosition = map(data, 0, 1023, 0, 100);
        Serial.print("Potentiometer at ");
        Serial.print(currentPosition);
        Serial.println("%");

        long difference = currentPosition-x;
        Serial.print("Difference :");
        Serial.println(difference);

    if(difference>0){

        State = UpState;

    }

    if(difference>0){

       State = DownState;
    }

    if(difference==0){

       State = IdleState;
    }

     switch (State) {

                   case IdleState:
                   Serial.println("Idle State");
                    HALT();
                    if((currentPosition-number)<0){
                     State = UpState;
                    }
                    if((currentPosition-number)>0){
                     State = DownState;
                    }
                    break;

                  case UpState:
                  Serial.println("Up State");
                    //Need to move down
                    DOWN();
                    if((currentPosition-number)>0){
                     State = DownState;
                    }
                    if((currentPosition-number)==0){
                     State = IdleState;
                    }
                    break;

                  case DownState:
                  Serial.println("Down State");
                    //Need to move up
                    UP();
                    if((currentPosition-number)<0){
                     State = UpState;
                    }
                    if((currentPosition-number)==0){
                     State = IdleState;
                    }
                    break;

     }

    }

    void DOWN(){
        analogWrite(enA, MotorSpeed);
        digitalWrite(in1, HIGH);
        digitalWrite(in2, LOW);
      }

    void UP() {
        analogWrite(enA, MotorSpeed);
        digitalWrite(in1, LOW);
        digitalWrite(in2, HIGH);

      }

    void HALT () {
        digitalWrite(in1, LOW);
        digitalWrite(in2, LOW);
    }
```

body:
For one thing, `currentPosition` is not declared `volatile` so the compiler may be keeping that value in a register, which is not consulted inside the ISR.

I'm also concerned about all the serial prints at 9600 baud (quite slow) which may make the position skip from 49 to 51 while you are busy printing values.

Comparing to be exactly equal in order to do something is always fraught.

---

       x=Serial.parseInt();
        old_x=x;
        toggle=1;
      }

      if((Serial.available())&&(toggle==1)&&(Serial.parseInt()!=old_x)){
          toggle=0;
      }

        if((toggle==1)&&(Serial.parseInt()==0)){
          toggle=0;
      }

Are you expecting three integers from serial?


body:
First, read Nick Gammon's answer: all his points are perfectly valid. He
notes that the serial prints can be quite slow. And indeed, as I counted
the characters, I find that the prints should take _at least_ 54 ms
per loop iteration. This is really very slow. In addition to this, the
calls to `parseInt()` can be much slower yet, especially considering
that one of them is not conditioned on `Serial.available()`.

Currently, the code that takes care of reading the potentiometer and
stopping the actuator looks like this:

```c++
int currentPosition;

// Triggered every 125 µs.
ISR(TIMER2_COMPA_vect) {
    if (currentPosition == 50) HALT();
}

void loop() {
    // Potentially extremely slow code...
    currentPosition = map(analogRead(linPot), 0, 1023, 0, 100);
    // Definitely very slow code: takes at least 54 ms.
}
```

This is reading the potentiometer _at best_ every 54 ms, and
potentially much more slowly. On every read, `currentPosition` is
updated. In parallel, the value of `currentPosition` is being tested
every 125 µs.

Note that there is really no point in testing `currentPosition` that
often. Once the value has been tested, testing it again before it is
updated serves no purpose. Your code would actually be a tiny bit faster
if you test the value right after updating it:

```c++
void loop() {
    // Potentially extremely slow code...
    currentPosition = map(analogRead(linPot), 0, 1023, 0, 100);
    if (currentPosition >= 50) HALT();
    // Definitely very slow code: takes at least 54 ms.
}
```

Note that I changed the equality test to an inequality test, for a
reason explained in Nick Gammon's answer.

You still have the problem that the loop is very slow. If you want the
potentiometer to be tested more frequently, you have several options.

1. The bad option: do it in the interrupt handler:

   ```c++
   // Triggered every 125 µs.
   ISR(TIMER2_COMPA_vect) {
       currentPosition = map(analogRead(linPot), 0, 1023, 0, 100);
       if (currentPosition >= 50) HALT();
   }
   ```

   This is a bad option because `analogRead()` takes at least
   112 µs, which means that the ISR will eat 98.6% of the CPU
   cycles. You could make this work kind of reasonably if you lower the
   interrupt frequency to something like 1 kHz or below. Still,
   such a long ISR is not really good practice.

2. The better option: make loop non-blocking:

   ```c++
   void loop() {
       // Non-blocking, very fast code.
       currentPosition = map(analogRead(linPot), 0, 1023, 0, 100);
       if (currentPosition >= 50) HALT();
       // More very fast code.
   }
   ```

   To read the serial port in a non-blocking way, see [Reading Serial on
   the Arduino][majenko]. For writing to the serial port in a
   non-blocking way, simply refrain to print very frequently.

3. The hard option: configure the ADC to read continuously.

   You can program the ADC in “self-running mode”: it will then take a
   reading every 104 µs. You can program it to also deliver an
   interrupt every time a new reading is available: you can test the
   reading in this interrupt handler. This will give you the best
   possible response time:

   ```c++
   void setup() {
       // Set the ADC to free running mode.
       // Enable the ADC interrupt.
   }

   volatile int raw_adc_reading;

   // Triggered on every fresh ADC reading.
   ISR(ADC_vect) {
       raw_adc_reading = ADC;
       if (raw_adc_reading >= RAW_THRESHOLD) STOP();
   }
   ```

   Note that I prefer to test the raw reading rather than the converted
   one. This is because `map()` is slow (it involves a long division)
   and an ISR should ideally be as fast as possible.

   You will have to dig into the MCU datasheet to learn how to configure
   the ADC in free running mode.

[majenko]: https://majenko.co.uk/blog/our-blog-1/reading-serial-on-the-arduino-27


message:
How to add one JsonDocument to another in ArduinoJson

I'm utilizing this json library: https://arduinojson.org/

I am attempting to write a function that creates a response object, and wraps an already built json document:

```
    void sendResponse(
            ResponseType state,
            JsonDocument *response
    ) {
        DynamicJsonDocument doc(256);

        doc[F("state")] = responseTypeFromEnum(state);
        doc[F("response")] = response; //breaks; how to do?

        this->sendJson(&doc);
    }
```

This fails of course, and I don't see a great solution anywhere...

I know I could use `createNestedObject()`, but this seems to require re-creating the given json object by hand? This would be a sub-optimal case.

Is there a way to easily wrap an existing JsonDocument in another?

Looking to take

```
{
  "some": "other document"
}
```

And wrap it like
```
{
  "state":"OK"
  "response": {
    "some": "other document"
  }
}
```

body:
You can add a [`JsonDocument`][1] inside another one, but you must pass the document by value, not by pointer.
Since you receive a pointer, you need to dereference it before trying to assign:

```c++
doc[F("response")] = *response;
```

**Node 1**: you could avoid this problem by passing `response` by reference, like so:

```c++
void sendResponse(ResponseType state, const JsonDocument &response) {
  DynamicJsonDocument doc(256);

  doc[F("state")] = responseTypeFromEnum(state);
  doc[F("response")] = response;

  this->sendJson(doc);
}
```

**Node 2**: calling the assignment operator (`=`) causes a deep copy of the `response` document. You could avoid this copy by calling [`shallowCopy()`][2] instead:

```c++
doc[F("response")].shallowCopy(response);
```

**Node 3**: unfortunately [`shallowCopy()`][2] is unavailable on ArduinoJson 7.

  [1]: https://arduinojson.org/v6/api/jsondocument/
  [2]: https://arduinojson.org/v6/api/jsonvariant/shallowcopy/


message:
Serial does not read buffer with integer characters greater than 43

I'm trying to write a script to move an object coupled to a linear axis through a `stepper motor`. The user must send information such as the `length` to be moved, the `speed` of movement, the `direction` of movement, or even if he wants to make millimetric adjustments via the `serial`. However, `I can't read lengths from 43 mm` where I `send` the `integer 43 over serial`. I tested several methods that I found on the internet. Below is the current code and some alternatives of the serial read section that failed.

```
void(* resetFunc) (void) = 0;

//Serial read
const int bufferSize = 30; // Tamanho máximo para o buffer de leitura
char buffer[bufferSize];   // Buffer para armazenar os dados lidos via serial

//Step motor
const int stepPin = 3;
const int senPin = 2;
const int enPin = 8;
int sen, sp, len, ad; //sen = forward or backward, sp = speed, len = length, ad = enable steps to adjustment
int REV;//motor revolutions
int time_motor; // interval of pulse (on/off)

void setup()

{

  pinMode(stepPin,OUTPUT);
  pinMode(senPin,OUTPUT);
  pinMode(enPin,OUTPUT);
  digitalWrite(enPin,LOW);

  Serial.begin(9600);

  while (!Serial.available()) {
    delay(10);
  }

  int bytesRead = Serial.readBytesUntil('\n', buffer, bufferSize);

  buffer[bytesRead] = '\0';

  sscanf(buffer, "%d,%d,%d,%d", &ad, &sen, &len, &sp);

  Serial.print("ad: ");
  Serial.println(ad);
  Serial.print("sen: ");
  Serial.println(sen);
  Serial.print("len: ");
  Serial.println(len);
  Serial.print("sp: ");
  Serial.println(sp);

  time_motor = 100;

  REV = int(768 * len);

  if(ad == 0){
    if (sen == 1){
      backward(REV, time_motor);
      }

    else {
      forward(REV, time_motor);
      }

      resetFunc();
  }
  else{
    if(sen == 1){backward(768, time_motor);resetFunc();}
    else{forward(768, time_motor);resetFunc();}
  }
}

void forward(int len_fact, int time_c) {
  digitalWrite(enPin, LOW);
  digitalWrite(senPin, HIGH);
  for (int x = 0; x < len_fact; x++) {
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(time_c);
    digitalWrite(stepPin, LOW);
    delayMicroseconds(time_c);
  }
}

void backward(int len_fact, int time_c) {
  digitalWrite(enPin, LOW);
  digitalWrite(senPin, LOW);
  for (int x = 0; x < len_fact; x++) {
    digitalWrite(stepPin, HIGH);
    delayMicroseconds(time_c);
    digitalWrite(stepPin, LOW);
    delayMicroseconds(time_c);
  }
}

void loop()
{

}
```
An alternative below:
```
  while (!Serial.available()) {
    // Aguarda até que haja dados disponíveis na porta serial
  }

  delay(100); // Pequeno atraso para garantir que todos os dados tenham chegado

  int bytesRead = 0;
  while (Serial.available() && bytesRead < bufferSize - 1) {
    char c = Serial.read();
    if (c == '\n') {
      break; // Termina a leitura ao encontrar uma quebra de linha
    }
    buffer[bytesRead] = c;
    bytesRead++;
  }

  // Adiciona o caractere nulo para indicar o final da string
  buffer[bytesRead] = '\0';

  // Usa a função sscanf para extrair os números do buffer
  sscanf(buffer, "%d,%d,%d,%d", &ad, &dir, &len, &sp);

  // Imprime os valores lidos para verificá-los
  Serial.print("ad: ");
  Serial.println(ad);
  Serial.print("dir: ");
  Serial.println(dir);
  Serial.print("len: ");
  Serial.println(len);
  Serial.print("sp: ");
  Serial.println(sp);
```
And the other:

```
  while (!Serial.available()) {
    // Aguarda até que haja dados disponíveis na porta serial
  }

  // Lê os dados da porta serial e armazena no buffer até atingir o tamanho máximo
  int bytesRead = 0;
  while (bytesRead < bufferSize - 1) {
    if (Serial.available()) {
      char c = Serial.read();
      if (c == '\n') {
        break; // Termina a leitura ao encontrar uma quebra de linha
      }
      buffer[bytesRead] = c;
      bytesRead++;
    }
  }

  // Adiciona o caractere nulo para indicar o final da string
  buffer[bytesRead] = '\0';

  // Usa a função sscanf para extrair os números do buffer
  sscanf(buffer, "%d,%d,%d,%d", &ad, &dir, &len, &sp);

  // Imprime os valores lidos para verificá-los
  Serial.print("ad: ");
  Serial.println(ad);
  Serial.print("dir: ");
  Serial.println(dir);
  Serial.print("len: ");
  Serial.println(len);
  Serial.print("sp: ");
  Serial.println(sp);
```
Serial returns nothing or "?". How should I proceed to solve this problem?
I'm using an original Arduino uno and writing in the arduino IDE. The version is 1.8.19.

body:
Well, you didn't provided that much info, but i picked up on some of your code (below) and in the serial monitor i can read all the numbers :

        const int bufferSize = 30; // Tamanho máximo para o buffer de leitura
    char buffer[bufferSize];   // Buffer para armazenar os dados lidos via serial

    //Step motor
    const int stepPin = 3;
    const int senPin = 2;
    const int enPin = 8;
    int dir, sp, len, ad; //sen = forward or backward, sp = speed, len = length, ad = enable steps to adjustment
    int REV;//motor revolutions
    int time_motor; // interval of pulse (on/off)

    void setup() {
      // put your setup code here, to run once:
      Serial.begin(9600);
    }

    void loop() {
      // put your main code here, to run repeatedly:
    while (!Serial.available()) {
        // Aguarda até que haja dados disponíveis na porta serial
      }

      delay(100); // Pequeno atraso para garantir que todos os dados tenham chegado

      int bytesRead = 0;
      while (Serial.available() && bytesRead < bufferSize - 1) {
        char c = Serial.read();
        if (c == '\n') {
          break; // Termina a leitura ao encontrar uma quebra de linha
        }
        buffer[bytesRead] = c;
        bytesRead++;
      }

      Serial.println(buffer);

      // Adiciona o caractere nulo para indicar o final da string
      buffer[bytesRead] = '\0';

      // Usa a função sscanf para extrair os números do buffer
      sscanf(buffer, "%d,%d,%d,%d", &ad, &dir, &len, &sp);

      // Imprime os valores lidos para verificá-los
      Serial.print("ad: ");
      Serial.println(ad);
      Serial.print("dir: ");
      Serial.println(dir);
      Serial.print("len: ");
      Serial.println(len);
      Serial.print("sp: ");
      Serial.println(sp);
    }

[![enter image description here][1]][1]

  [1]: https://i.stack.imgur.com/tfinL.png


message:
A fatal error occurred: Could not open /dev/ttyUSB0, the port doesn't exist (UART bridge CP2102)

I can't upload my program to ESP32-CAM. It just keeps saying the port doesn't exist. But I can see it in /dev/ttyUSB0 (By the way, I'm on linux, Fedora)
The UART bridge is CP2102 Silicon Labs.

What I've tried:

 - Using both IDE 1, 2
 - Removing everything, trying again on IDE 1
 - upgrading permissions

Any help will be appreciated.

---

[![enter image description here][1]][1]
[![enter image description here][2]][2]

After `sudo dmesg -wT | grep cp2102` as suggested by @timemage, I got this:[![enter image description here][3]][3]

---

  [1]: https://i.stack.imgur.com/XwXPK.png
  [2]: https://i.stack.imgur.com/z4woLl.jpg
  [3]: https://i.stack.imgur.com/xSKww.png

body:
A [post][1] by [Bee_HapBee][2] on Reddit solved my issue! Thank you!

```
sudo chmod 666 /dev/ttyUSB0
```

> Yep, I wish esptool.py would've told me that I needed permissions, rather than the port doesn't exist

  [1]: https://www.reddit.com/r/esp32/comments/ybzduf/took_me_1_hour_to_make_a_hello_world/
  [2]: https://www.reddit.com/user/Bee_HapBee/


message:
How to refresh an iframe in a page made with Espasyncwebserver

So, I have this page on esp8266:
```c++
  controlserver.on("/UDEL", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send(200, "text/html", htmltd);
  });
```
```htmltd ``` is a string, generated by a function and it contains some forms, and they run in iframe tag,
```html
<FORM action="/process" method="post" id="config" target="iframe">

</form>

<iframe style="visibility: hidden;" src="http://" )+local_IPstr+"/UDEL"  name="iframe"></iframe>
```
and processed by:
```c++
controlserver.on("/process", HTTP_POST, [](AsyncWebServerRequest *request) {
.
.
.
request->send(200, "text/html", HTML_CSS_STYLING + "<script>alert(\" Deleted \")</script>");
.
.
.
});
```
They work perfectly fine, and after clicking on submit button the page shows an alert, and it must be reloaded, because the submitted form must be removed from the page. it happens when I reload the page manually. but I want it to happen automatically after each form submission. it tried many ways like :
```html
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>Reload iFrame</title>
  </head>
  <body>
    <iframe src="https://www.w3schools.com" id="myIframe"></iframe>

  <input onclick="reloadIframe()"  type="button" value="Click me">

    <script>
      function reloadIframe() {
        var iframe = document.getElementById("myIframe");
        iframe.contentWindow.location.reload();
      }
    </script>
  </body>
</html>

```
but it doesn't work in esp8266.

body:
From my understanding, your intention is to automatically reload the main page (which contains the form and the iframe) after submitting the form. but the challenge is that the form submits inside the iframe so when you send a response to the iframe, it won't directly impact the main page.

I believe you could use a small trick to work this problem around.

1- After successfully processing the form data inside the iframe, send back a script that communicates with the parent window (the main page) and instructs it to reload

2- In the main page, listen to the received message and then reload.

Here is how to implement the proposed solution:

On your ESP8266 route handler, send a script in the response to post a message to the parent window after processing the form:

```python
controlserver.on("/process", HTTP_POST, [](AsyncWebServerRequest *request) {
    //add your processing code
    String response = HTML_CSS_STYLING +
                      "<script>"
                      "window.parent.postMessage('reloadPage', '*');"
                      "</script>";
    request->send(200, "text/html", response);
});
```

window.parent.postMessage will send "reloadPage" string from iframe to parent window. And on your main page (the page that contains the iframe), listen for this message and reload the entire page when the message is received:

    <FORM action="/process" method="post" id="config" target="iframe">
        <!-- form field here -->
    </form>

    <iframe style="visibility: hidden;" src="http://"+local_IPstr+"/UDEL" name="iframe"></iframe>

    <script>
        // listen for messages from iframes
        window.addEventListener('message', function(event) {
            // Await reloadPage message
            if(event.data === 'reloadPage') {
                location.reload();
            }
        });
    </script>

Btw instead of using an iframe, you could use AJAX to submit the form so that you get a response directly from the server and refresh the page using `location.reload()`. This way you can submit form data (or retrieve data) without refreshing the entire page. Only the necessary parts of the page updates.

I hope that this helps, if not, please inform me.


message:
ArduinoJson reading `null` from Serial

I have a setup that reads from serial when I sense that there is something to be read (and always assume that what is sent to the arduino is valid json):

```
void setup(){
    Serial.begin(9600);
    while (!Serial) continue;
}

void loop() {

    if(Serial.available()){
        StaticJsonDocument<256> doc;

        deserializeJson(doc, Serial);

        serializeJson(doc, Serial);
        Serial.println();
    }
}

```

Given the following input from ArduinoIDE's serial monitor (Set to `newline` setting, `9600` baud):

```
{"hello": "world"}
```

This produces the following:

```
{"hello": "world"}
null
```

I have two questions:

 - Is this setup correct/ how I should be waiting and retrieving json from serial?
 - Why the additional `null` input? Looks like there is something still in the serial buffer even after the first iteration?
 - <strike>How to detect the second case where the resulting document gets re-serialized as `null`? Comparing to `0`, `NULL`, and `nullptr` seem to not work</strike> Figured this one out, found out about `DeserializationError`

Upon utilizing `DeserializationError`, looks like the `null` parsing had an error of `EmptyInput`

body:
As observed on your `serial console` settings, it mentions both **newline** and **9600 baud**. Let's break this down:

### **Issue with Serial Communication**

1. **Partial Payloads**: You are currently assuming that when `Serial.available()` returns `true`, the entire JSON payload has been received. However, due to the nature of serial communication (especially at 9600 baud), data can arrive in fragmented chunks. Invoking `deserializeJson()` on a partial JSON payload can result in incomplete or corrupted data.

2. **End-of-Message Ambiguity**: Lacking a definitive end-of-message marker makes it challenging to discern when a complete JSON payload has been received. For instance, when sending `{"hello": "world"}` from the Arduino IDE's serial monitor, it automatically appends a newline (or a carriage return based on your configuration). This newline is then misinterpreted as another JSON payload, leading to the undesired `null` output.

### **How you can solve this:**

1. **Use a Delimiter**: Choose a specific character or sequence to act as an end-of-message delimiter. The newline character (`\n`) is a typical choice, especially if data is exclusively sent from the Arduino IDE's serial monitor. Nevertheless, if you anticipate newlines within your JSON data, you might consider another distinct character, like `#`.

2. **Read Until Delimiter**: Adjust your code to continuously read characters from the serial port until the chosen delimiter is encountered. Upon receipt of the entire message, it can then be parsed.

### **Code Example**

Here's a sample code employing the newline character as a delimiter:

```cpp
const int maxBuffer = 256;
char serialBuffer[maxBuffer];
int bufferPos = 0;

void setup() {
    Serial.begin(9600);
    while (!Serial) continue;
}

void loop() {
    if (Serial.available()) {
        char inChar = Serial.read();

        if (inChar == '\n') {  // EOM
            serialBuffer[bufferPos] = '\0';
            processMessage(serialBuffer);
            bufferPos = 0;  // Reset buffer pos
        } else if (bufferPos < maxBuffer - 1) {  // Avoid buffer overflow
            serialBuffer[bufferPos++] = inChar;
        }
    }
}

void processMessage(char* message) {
    StaticJsonDocument<256> doc;

    DeserializationError error = deserializeJson(doc, message);

    if (error) {
        Serial.println("Failed to parse JSON");
    } else {
        serializeJson(doc, Serial);
        Serial.println();
    }
}
```
This way you ensure the entirety of message is parsed and received and therefore avoiding unwanted `null` outputs.

I hope this helps ^_^


message:
Arduino Pro Micro not recognizing INPUT or INPUT_PULLUP

I tried to make a controller box with multiple `buttons`. Sadly, when I tried to connect the buttons, the `Arduino Pro Micro` didn't recognize them being pressed. I even tried to connect a wire directly (and a directly a resistor from GND to the ports) from GND to the ports but it doesn't seem to matter.

`OUTPUT works` on the same ports, but `INPUT/INPUT_PULLUP` does not.
Is there something wrong with the code?

My `Arduino Pro Micro` is a Chinese knockoff. Keyboard and Mouse are working, OUTPUT is working. It doesn't seem to work with the input.

PS: I have worked with Arduino UNO before (and also the ESP family (ESP8266, ESP32)).

PS2: Sometimes, if I touch the microcontroller's back side some values register (like I pushed all the buttons at once)

```c++
#define LED_PIN 4
#define BUTTON_1 10
#define BUTTON_2 16
#define BUTTON_3 14
#define BUTTON_4 9

byte ledState = LOW;

void setup() {
  Serial.begin(9600);
  pinMode(LED_PIN, OUTPUT);
  pinMode(BUTTON_1, INPUT_PULLUP);
  pinMode(BUTTON_2, INPUT_PULLUP);
  pinMode(BUTTON_3, INPUT_PULLUP);
  pinMode(BUTTON_4, INPUT_PULLUP);
}

void loop() {

  byte one = digitalRead(BUTTON_1);
  byte two = digitalRead(BUTTON_2);
  byte three = digitalRead(BUTTON_3);
  byte four = digitalRead(BUTTON_4);

  if (one == HIGH) {
    Serial.println("BUTTON_1");
  }
  if (two == HIGH) {
    Serial.println("BUTTON_2");
  }
  if (three == HIGH) {
    Serial.println("BUTTON_3");
  }
  if (four == HIGH) {
    Serial.println("BUTTON_4");
  }

  digitalWrite(LED_PIN, ledState);
  ledState = !ledState;
  delay(1000);
}
```

Edit: corrected the code

Mention: I wired the buttons the following way (I have to mention it, because the Arduino Pro Micro doesn't have a sepparate 3V/5V pin, it only has RAW output that by my undertanding can fry the board)

Tutorial from where I inspired the button wiring:
https://arduinogetstarted.com/tutorials/arduino-button

<img src="https://arduinogetstarted.com/images/tutorial/arduino-button-wiring-diagram.jpg">

body: The way you have it wired, INPUT_PULLUP will make the buttons look HIGH, so in your code you need to test if they are going LOW, which is what grounding the button would do.


body:
After looking at many tutorials and trying many approaches with different Arduinos (Uno, because it's easyer to prototype) (and taking a short brake so I can try again from 0 with a new mindset) I made it work.

Before, I could do it because I was using Microcontrollers that had a 3/5V output also (ex. Uno, Mega, Nano, STM32, ESP8266, ESP32), so I could do a pull-up/down circuit, but because the Arduino Micro doesn't have such pins (it has only RAW as output, which can fry the board if it's externally powered) I had to use this method where I only use a GND pin and a Digital Input without any ressistors wired to the button.

Thanks for the answers and suggestions!

The new code (without the LED functionality):

```
#include "Keyboard.h"

// defining button pin numbers
// TODO: rename variables according to functionality
#define BUTTON_10 10
#define BUTTON_16 16
#define BUTTON_14 14
#define BUTTON_9 9

// giving them a first-state of HIGH
int previousButtonState10 = HIGH;
int previousButtonState16 = HIGH;
int previousButtonState14 = HIGH;
int previousButtonState9 = HIGH;

void setup() {
  // initializing the buttons as INPUTS with PULLUP (internal pull-up resistor from Arduino)
  pinMode(BUTTON_10, INPUT_PULLUP);
  pinMode(BUTTON_16, INPUT_PULLUP);
  pinMode(BUTTON_14, INPUT_PULLUP);
  pinMode(BUTTON_9, INPUT_PULLUP);

  // only for test
  // TODO: Move this only to the function needed when more functionality is added
  Keyboard.begin();

}

void loop() {
  // checking if any of the buttons were pressed and saving the state in a variable
  previousButtonState10 = checkButton(BUTTON_10, previousButtonState10);
  previousButtonState16 = checkButton(BUTTON_16, previousButtonState16);
  previousButtonState14 = checkButton(BUTTON_14, previousButtonState14);
  previousButtonState9 = checkButton(BUTTON_9, previousButtonState9);
}

// function: reads the button state and compares it with the previous state to find out if it was pressed or not
// params: buttonPin => the pin number of the button; previousButtonState => the state corresponding for each button
// return: it returns the red state, so it can be saved as previousState in the coresponding parameter
int checkButton(int buttonPin, int previousButtonState) {
  int buttonState = digitalRead(buttonPin);

  if (buttonState == LOW && previousButtonState == HIGH) {
    Keyboard.println(buttonPin);
    // some minimal debouncing
    // TODO: WIll be a problem when using millis() in the future
    delay(50);
  }

  if (buttonState == HIGH && previousButtonState == LOW) {
    // not needed, but some functionality could be added in the future
    // Keyboard.println("release");
    delay(50);
  }

  return buttonState;
}

```

Now I can work further on improving and extending the code to make the "Macro Board" project with mouse movement (and I also have to solder the buttons and LEDs to the board :P )


message:
Limit of EthernetClient connections

I'm working on a project on which I need to have multiple EthernetClient connections to different servers. All of these connections must be kept alive simultaneously and by this I mean I cannot stop or close one of these clients before starting the other.

Currently I can keep 2 simultaneous successful EthernetClient connections. After this, any subsequent client fails to connect to any server. The following code is running on an ESP32-S3 with a W5500 Ethernet module.

```c++
#include <Arduino.h>
#include <EthernetLarge.h>
#include <SPI.h>

#define     SPI_MOSI    35
#define     SPI_MISO    37
#define     SPI_SCK     36
#define     ETHERNET_CS 38

SPIClass SPI_Ethernet;
EthernetClient ethCli1;
EthernetClient ethCli2;
EthernetClient ethCli3;
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };

void setup()
{
  Serial0.begin(115200);
  SPI_Ethernet.begin(SPI_SCK, SPI_MISO, SPI_MOSI, ETHERNET_CS);

  pinMode(39, OUTPUT);
  pinMode(47, OUTPUT);
  digitalWrite(47, HIGH);
  digitalWrite(39, LOW);
  delay(500);
  digitalWrite(39, HIGH);

  Ethernet.init(ETHERNET_CS);
  Ethernet.begin(mac);
  Serial0.println(Ethernet.localIP());

  if( !(ethCli1.connect("httpbin.org", 80)) )
      Serial0.println("connection > 1 < failed");
  else
    Serial0.println("connection > 1 < succeeded");

  if( !(ethCli2.connect("httpbin.org", 80)) )
    Serial0.println("connection > 2 < failed");
  else
    Serial0.println("connection > 2 < succeeded");

  if( !(ethCli3.connect("httpbin.org", 80)) )
    Serial0.println("connection > 3 < failed");
  else
    Serial0.println("connection > 3 < succeeded");
}

void loop()
{
}
```

Which outputs:
```
connection > 1 < succeeded
connection > 2 < succeeded
connection > 3 < failed
```

In this code I'm using the OPEnSLab-OSU/EthernetLarge Ethernet library. But I also tried to run it with the Ethernet.h with the same output. In the W5500 documentation I was able to find the information that it can keep up to 8 connections open, but I wasn't able to find if the ESP32 has any restrictions like a max of simultaneous connections. Is it possible to keep more than 2 connections alive simultaneously?

In short:
- I'm using an ESP32-S3 with a W5500 Ethernet Module.
- I can keep 2 simultaneous connections and closing previous connections before opening a new one works, but in my project I need to keep at least 3 simultaneous connections.
- Changing from OPEnSLab-OSU/EthernetLarge Ethernet library to Ethernet.h produced the same output.
- Adding a delay between the connections didn't work.
- In the example code all the connections are being established to the same server, but in my official project these connections are established to different servers. Either way the output is the same.
- The W5500 documentation says that it can keep up to 8 simultaneous connections. I wasn't able to find if ESP32 has any restrictions on the limit of simultaneous connections.

body:
The `OPEnSLab-OSU/EthernetLarge` library by default defines `MAX_SOCK_NUM` to `2`. Increasing this value allowed me to keep more simultaneous connections.

Regarding the `Ethernet.h` library, I also checked it and it was already setting `MAX_SOCK_NUM` to `8`. Testing the code again with it also allowed me to keep more simultaneous connections. Why I wasn't able to keep them before when using `Ethernet.h` it is still a mystery to me.