# Question
Title: SNMP Manager - Multiple IP address -issue
I have multiple SNMP devices on the same network and I am trying to request, *via OID numbers*, each SNMP device and assign the **response** into an array. When I request a single IP, I get the correct response as expected.

**Problem:** If I run the same code in a for loop (*multiple ip's 192.168.1.150, 192.168.1.151, etc*), I get duplicate info. *I might be using the wrong callback method, or the SNMP Manager can not dynamically change the ip address..* I have researched a lot of topics and tried many avenues, but I can't get past this point.

**If anyone can assist me, it would help a lot!!**

---

**Example Output:** *The model name and serial should be different on each ip*

```
----------------------
192.168.8.150
KONICA MINOLTA bizhub C658
A79J021002278
----------------------
192.168.8.151
KONICA MINOLTA bizhub C658
A79J021002278
----------------------
192.168.8.152
KONICA MINOLTA bizhub C658
A79J021002278
----------------------
192.168.8.153
KONICA MINOLTA bizhub C658
A79J021002278
----------------------
192.168.8.154
KONICA MINOLTA bizhub C658
A79J021002278

```

**Here is the code**

```
#if defined(ESP8266)
#include <ESP8266WiFi.h> // ESP8266 Core WiFi Library
#else
#include <WiFi.h>        // ESP32 Core WiFi Library
#endif

#include <string.h>
#include <WiFiUdp.h>
#include <Arduino_SNMP_Manager.h>

//************************************
//* Your WiFi info                   *
//************************************
const char *ssid = "Workmin_Sales";
const char *password = "workmin92429242";
//************************************

//************************************
//* SNMP Device Info                 *
//************************************
const char *community = "public";
const int snmpVersion = 1; // SNMP Version 1 = 0, SNMP Version 2 = 1
// OIDs
const char *oidModelName = ".1.3.6.1.2.1.25.3.2.1.3.1";               // OctetString SysName
const char *oidSerialNumber = ".1.3.6.1.2.1.43.5.1.1.17.1";              // OctetString SysName
//************************************

//************************************
//* Settings                         *
//************************************
int pollInterval = 20000; // delay in milliseconds
//************************************

//************************************
//* Initialise                       *
//************************************
// Variables
char *modelNameArray[5];
char *serialNumberArray[5];

char modelName[50];
char *modelNameResponse = modelName;
char serialNumber[50];
char *serialNumberResponse = serialNumber;

// Blank callback pointer for each OID
ValueCallback *callbackSerialNumber;
ValueCallback *callbackModelName;
//************************************

unsigned long pollStart = 0;
// SNMP Objects
WiFiUDP udp;                                           // UDP object used to send and receive packets
SNMPManager snmp = SNMPManager(community);             // Starts an SMMPManager to listen to replies to get-requests
SNMPGet snmpRequest = SNMPGet(community, snmpVersion); // Starts an SMMPGet instance to send requests

//************************************
//* Function declarations            *
//************************************
void getSNMP();
//************************************

void setup()
{
  Serial.begin(115200);
  WiFi.begin(ssid, password);
  Serial.println("");
  // Wait for connection
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to SSID: ");
  Serial.println(ssid);
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());

  snmp.setUDP(&udp); // give snmp a pointer to the UDP object
  snmp.begin();      // start the SNMP Manager
}

void loop()
{
  // put your main code here, to run repeatedly:
  snmp.loop();
  if (millis() - pollStart >= pollInterval)
  {
    pollStart += pollInterval; // this prevents drift in the delays

    getSNMP();
    // doSNMPCalculations(); // Do something with the data collected
  }
}

void getSNMP()
{
  for (int i = 0; i < 5; i++) {
    // Build a SNMP get-request add each OID to the request
    IPAddress router(192, 168, 8, i + 150);

    // Get callbacks from creating a handler for each of the OID
    callbackSerialNumber = snmp.addStringHandler(router, oidSerialNumber, &serialNumberResponse);
    callbackModelName = snmp.addStringHandler(router, oidModelName, &modelNameResponse);

    snmpRequest.addOIDPointer(callbackSerialNumber);
    snmpRequest.addOIDPointer(callbackModelName);

    snmpRequest.setIP(WiFi.localIP()); // IP of the listening MCU
    // snmpRequest.setPort(501);  // Default is UDP port 161 for SNMP. But can be overriden if necessary.
    snmpRequest.setUDP(&udp);
    snmpRequest.setRequestID(rand() % 5555);
    snmpRequest.sendTo(router);
    snmpRequest.clearOIDList();
    delay(1000);

    modelNameArray[i] = modelNameResponse;
    serialNumberArray[i] = serialNumberResponse;
    Serial.print("192.168.8.");
    Serial.println(i + 150);
    Serial.println(modelNameArray[i]);
    Serial.println(serialNumberArray[i]);
    Serial.println("----------------------");
  }
}

```

# Answer
I think I see multiple issues with the example above.

1. The `snmpRequest.sendTo(router);` will send the SNMP packet out. But you need to call `snmp.loop()` to read the incoming replies to your request. So you need to restructure the code so that you can call loop() potentially many times in order to wait for the incoming replies before you read and store the values.
2. `serialNumberResponse` is a pointer to a character array `serialNumber` (likewise for the model). If the callback returned serial number `123ABC` the first time, and the next device was called `1XD` then the array would have a value of `1XDABC`. So if you plan to re-use the variable, you'll need to clear it between uses something like: `memset(serialNumber, 0, sizeof(serialNumber));`
3. As you might not always get a successful response, or a response within the time allowed, the value may be still blank, if you're looking to store the values in another variable, you may want to ensure they aren't empty, as this would overwrite the value you may have had back on a previously successful call. If you were dealing with numbers, the value might also be that of a previous call. As pointed out in the answer above, you're dealing with pointers, so if you want to store the value you need to copy the value out, otherwise, you'll just point to the same pointer.

I hope this helps point you in the right direction. I've added an example to the library to show how multiple devices can be queried and the results stored in an array, see: https://github.com/shortbloke/Arduino\_SNMP\_Manager/tree/master/examples/ESP\_Multiple\_SNMP\_Device\_Polling. It stores the responses directly into the array. This might cause values to be cleared in the event of a timeout, I've not tested it completely.

Martin
> 1 votes

# Answer
You're not storing the data in your array, you're storing a pointer to the storage where the callback stores its data. So every entry gets the same pointer to the same storage, which gets its content changed. So all the array entries see the same (last) content.

It took me many years to properly get my head around C pointers.

Instead of just assigning (`=`) the value you need to *copy the content*.

Since you just have an array of pointers that can be done with `strdup()` which allocates a new block of RAM and copies the contents to it. Be sure to use `free()` on that allocated block when you've finished with it.
> 1 votes

---
Tags: esp32, tcpip
---


# Question
Title: Prevent Resetting of Null Weight when using HX711 with a load cell
Helllo,
I am using the HX711 module and load cell with an arduino uno for force measurements. I am using this library.

I first use the example "Calibration" code for calibration with a 200 g weight. Then I save the calibration constant to the eeprom (choosing yes on the serial monitor). Then the load cell is able to measure weights accurately.

After that I remove the weight from the load cell and run this code after uncommenting the last line of this part of the above code:

```
LoadCell.begin();
  //LoadCell.setReverseOutput();
  float calibrationValue;
  calibrationValue = 696.0;
#if defined(ESP8266)|| defined(ESP32)
  //EEPROM.begin(512);
#endif
  EEPROM.get(calVal_eepromAdress, calibrationValue); // I have uncommented this

```

The weights are measured accurately.

**But when before powering the arduino, if I keep a weight on the load cell that weight is taken to be 0.**

For this I have done the following change to the code:

```
boolean _tare = false;

```

But I get the following output on the serial monitor (Note: The following output is obtained on startup when there is/there is no weight on the load cell):

**Questions:** What is the use of the following line:

```
calibrationValue = 696.0; // uncomment this if you want to set the calibration value in the sketch

```

Is it useless for the code I am using above? Because I am using the calibration value from the eeprom.

Q2) Why is it showing -39000 as an output value? And how to correct it?

**Alternate Statement:** In other words, I want to use the HX711 module with the arduino and a load cell. I will first calibrate it with a known weight and save the calibration value. Before powering up the arduino I will keep a weight on the load cell. After powering up the weight value should be the absolute value instead of making the Weight Null.

**EDIT1:** I incorporate the changes suggested in the answers by @Edgar Bonet and also make the problem more clear just in case. According to suggestions I have made the corresponding changes to the calibration code. Then I run that and the values are saved to eeprom. Code changes:

```
const int calVal_eepromAdress = 0;
const int tare_eepromAdress = sizeof(float);

```

and

```
#endif
        EEPROM.put(calVal_eepromAdress, newCalibrationValue);
        EEPROM.put(tare_eepromAdress, LoadCell.getTareOffset());
#if defined(ESP8266)|| defined(ESP32)
        EEPROM.commit();

```

Now, I wish to run the second script and for this to display the correct weights. This should work in all cases regardless of whether a weight has not been kept on the load cell or has been kept and should be independent of the weight that has been kept. To this script I have made the following changes:

```
const int calVal_eepromAdress = 0;
const int tare_eepromAdress = sizeof(float);

```

and

```
// Inside void setup()
void setup() {
  Serial.begin(57600); delay(10);
  Serial.println();
  Serial.println("Starting...");

  LoadCell.begin();
  //LoadCell.setReverseOutput(); //uncomment to turn a negative output value to positive
  float calibrationValue; // calibration value (see example file "Calibration.ino")
  float tareValue;
  calibrationValue = 696.0; // uncomment this if you want to set the calibration value in the sketch
  tareValue = 0;
#if defined(ESP8266)|| defined(ESP32)
  //EEPROM.begin(512); // uncomment this if you use ESP8266/ESP32 and want to fetch the calibration value from eeprom
#endif
  EEPROM.get(calVal_eepromAdress, calibrationValue); // uncomment this if you want to fetch the calibration value from eeprom
  EEPROM.get(tare_eepromAdress, tareValue);

  unsigned long stabilizingtime = 2000; // preciscion right after power-up can be improved by adding a few seconds of stabilizing time
  boolean _tare = true; //set this to false if you don't want tare to be performed in the next step
  LoadCell.start(stabilizingtime, _tare);
  if (LoadCell.getTareTimeoutFlag()) {
    Serial.println("Timeout, check MCU>HX711 wiring and pin designations");
    while (1);
  }
  else {
    LoadCell.setCalFactor(calibrationValue); // set calibration value (float)
    LoadCell.setTareOffset(tareValue);
    Serial.println("Startup is complete");
  }
}

```

**EDIT2:**

```
#if defined(ESP8266)|| defined(ESP32)
        EEPROM.begin(512);
#endif
        EEPROM.put(calVal_eepromAdress, newCalibrationValue);
        EEPROM.put(tare_eepromAdress, LoadCell.getTareOffset());

        Serial.println(newCalibrationValue);
        Serial.println(LoadCell.getTareOffset());

```

Output:

```
-206.90
8368790

```

In the second script:

```
#if defined(ESP8266)|| defined(ESP32)
  //EEPROM.begin(512); // uncomment this if you use ESP8266/ESP32 and want to fetch the calibration value from eeprom
#endif
  EEPROM.get(calVal_eepromAdress, calibrationValue); // uncomment this if you want to fetch the calibration value from eeprom
  EEPROM.get(tare_eepromAdress, tareValue);
  Serial.println(calibrationValue);
  Serial.println(tareValue);

```

Output:

```
-206.90
0.00

```

I am uploading my codes onto Github just in case. They can be found here.

Q) What is happening here?

**EDIT3:** The following changes make it work like a charm: In the "Calibration" script:

```
long tareValue = LoadCell.getTareOffset(); // Instead of float tareValue

```

Similarly in the second script:

```
long tareValue; // Instead of float tareValue

```

# Answer
In order to convert the raw ADC readings to a weight, the library needs two coefficients:

* a “tare offset”, which is the raw reading when there is no weight on the scale
* a gain, or “calibration factor”, which is the ratio of a change in the ADC reading to the corresponding change in weight.

The examples provided with the library use the EPPROM to store and retrieve the calibration factor, but not the tare offset. This makes sense as, in common usage, a weight scale is always zeroed at power up, or right after power up. This is usually desirable as one would often place an empty container on the scale which should not affect the displayed weight.

If you do not want to zero the scale at power-up, then you need your sketch to remember the tare offset in addition to the calibration factor. For this, you can use the methods of `LoadCell`:

```
// Get the tare offset (raw data value output without
// the scale "calFactor").
long getTareOffset();

// Set new tare offset (raw data value input without
// the scale "calFactor").
void setTareOffset(long newoffset);

```

Now, to the more specific questions:

> What is the use of the following line:
>
> ```
> calibrationValue = 696.0;
>
> ```

None. It is just an example. You are supposed to either replace this number with your measured calibration factor, or remove this line and read `calibrationValue` from the EEPROM.

> Why is it showing -39000 as an output value?

Because the tare offset has not been set, so it presumably defaults to zero.

---

**Edit**: Answering extra questions in comment.

> Do I need to store this value to the eeprom when running the calibration script?

You can store it whenever it is convenient to you. The calibration script seems a good place.

> I am not able to get this into code. I read the source files but I am unsure about what changes to make.

What you may try (untested):

1. right after the line

```
const int calVal_eepromAdress = 0;

```

add this:

```
const int tare_eepromAdress = sizeof(float);

```
2. Right after this:

```
EEPROM.put(calVal_eepromAdress, newCalibrationValue);

```

add this:

```
EEPROM.put(tare_eepromAdress, LoadCell.getTareOffset());

```
> 4 votes

---
Tags: arduino-uno
---


title: Static IP for ESP8266 based on gateway

text:
# Question
Title: Static IP for ESP8266 based on gateway
I'm new to Arduino programming. I want to make my ESP8266 get a static IP address based on the gateway's IP address.

I mean if the gateway is at 192.168.0.1 then the ESP8266 should get 192.168.0.15 as a static IP address. And if the gateway is at 192.168.1.1 then it should get 192.168.1.15 as an IP address.

# Answer
You can either set the router to allocate a static IP address based on your ESP8266's MAC address, or go the DHCP-way first, read the gateway IP address you got, and then do a `WiFi.config()`, something roughly like this (untested):

```
WiFi.begin(ssid, password);
IPAddress ip = WiFi.gatewayIP();
IP[3] = 15;
IPAddress dns(8, 8, 8, 8);
WiFi.config(ip, WiFi.gatewayIP(), dns, WiFi.subnetMask());

```

It is a bit of a trick, and not pretty, and you don't get to set the DNS as provided by the DHCP, because there is no `getDNS()`, for some silly reason, hence the use of Google's DNS server.

Note that when doing this, you run the risk of setting the ESP8266's IP address to an address already taken by another device on the same router.
> 1 votes

# Answer
Here is the idea that I have not implemented yet.

1. Connect to the wifi and let the router assign the IP to it.
2. After getting the IP from the router save that IP to eeprom
3. Now next time you want to connect to the wifi use this code.

```
// Set your Static IP address
IPAddress local_IP(192, 168, 1, 184);
// Set your Gateway IP address
IPAddress gateway(192, 168, 1, 1);

IPAddress subnet(255, 255, 0, 0);
IPAddress primaryDNS(8, 8, 8, 8);   //optional
IPAddress secondaryDNS(8, 8, 4, 4); //optional

if (!WiFi.config(local_IP, gateway, subnet, primaryDNS, secondaryDNS)) {
    Serial.println("STA Failed to configure");
  }

  // Connect to Wi-Fi network with SSID and password
  Serial.print("Connecting to ");
  Serial.println(ssid);
  WiFi.begin(ssid, password);

```

load the saved ip, gateWay and other information saved in the eeprom before passing to wifi.config function.
> 0 votes

---
Tags: esp8266, tcpip
---


# Question
Title: Is there a way to connect two Arduinos, when one of them has all of its pins occupied?
I want to connect an Arduino Uno to an Arduino Nano, so that it can send signals. The problem is that the Arduino Uno has a motor shield connected to it, and it takes up all pins of the Arduino.

This is a picture of the whole motor shield contraption if it helps:

Does anybody know any solution for this?

# Answer
Pins 0 and 1 are serial pins which are also connected to usb, and you use them when you are programming your board or when you send anything to serial. It is unlikely that any shield uses it unless it has to and it although has a benefit of being able to listen to what the Arduino sends. I think hitching a ride on pins 1 and 0 (rx/tx) would be the easiest. SO you can print or write to them the same way as you respond to yourself.

Just a warning that when you are sending data between two boards and Print numbers they come as symbols of the numbers, not the numbers themselves So `Serial.print(7)` would arrive to the next arduino as number 55 or symbol '7'. If you are sending numbers between two arduinos you can use write `Serial.write(7);` which does not change data, but your serial monitor on a computer wont read it right, or you can send them as symbols, but then the arduino listening may have to convert number symbol to the number. (sooner or later you will have to create yourself a simple function to convert symbols to numbers in your project...
> 2 votes

---
Tags: arduino-uno, arduino-nano, communication
---


title: Properly escaping very large strings

text:
# Question
Title: Properly escaping very large strings
On an ESP8266 I want to create a little webserver that shows me a dashboard with charts and stuff. For this I want to include the echarts-library as it works offline. To access it the only way I can see this working is that I write:

```
const char libData[784674] PROGMEM = "the entire 700 KB library goes here";

```

And then deliver it on request with `server.on('./echarts.min.js', handleLibRequest)` or something like that.

Now my problem is that in this 700KB of text there are `'` and `"` characters all scattered arround. The C++11 way of `R("hard escapable '"'''" string")` isn't working in my environment. How would one go about this to include this file in my code?

Is there mybe some way utilize the preprocessor for this? Or maybe an online tool that converts `"str" to ['s','t','r']`?

# Answer
Its simple, paste all you page between "()" on the below line

```
const char live_html[] PROGMEM = R"rawliteral(your date here)rawliteral";

```
> 1 votes

# Answer
You could write a program that escapes all the offending characters and use the output of that in your `const char libData[]`; see here for a list of escape sequences;

You could serve the library directly from a (pseudo) file system on the ESP8266, without having to copy it "manually" into a variable; you just copy the file to the filesystem;

You could Base64-encode the library and manually copy the result into `const char libData[]`, then Base64-decode before sending;

What I like to do, if there is no file system but enough memory:

* Gzip the library;
* Base64-encode the .gz file;
* Copy the Base-64 encoded result by hand into your `const char libData[]`.

The Base64 encoding allows you to copy/paste without problems.

Despite the Base64 encoding, the gzipping makes the end result smaller than the original, which helps with memory usage and transfer speed, and it will have no "quote problems".

When the libData needs to be served, Base64-decode it, and send the resulting (gzipped) data to the client; all browsers I know will accept that if you add the `Content-Encoding: gzip` header.

Example code on a raw client without a webserver library: `unsigned int sendBase64Page()` (mind the content type).
> 1 votes

# Answer
You can use "objcopy" to produce an object file from the file's contents, if you declare it as binary.

```
objcopy -I binary echarts.min.js -O <your-bfd-format> echarts.min.js.o

```

To find out which BFD format you need, run `objdump -t <any object file>` and look at its output.

The resulting object file contains an object named after the input file in the `.data` section. There are 3 symbols in the symbol table:

* \_binary\_echarts\_min\_js\_start
* \_binary\_echarts\_min\_js\_end
* \_binary\_echarts\_min\_js\_size

The "start" symbol marks the beginning of the file's content, and the "end" symbol marks the address **after** the last byte. The "size" symbol is hard to use in C or C++, because it is an absolute value.

Commonly I just use "start" and "end" like this:

```
extern const char _binary_x_bin_start[];
extern const char _binary_x_bin_end[];

```
> 1 votes

# Answer
I've just written myself now a python-script that creates a char-array with the numbers representing the characters. Maybe it helps someone else:

```
import sys

def arrayify(sourceFile, targetFile):
    with open(sourceFile, 'rb') as sf:
        contents = sf.read()

        charArray = ""

        for char in contents:
            charArray += str(char) + ","

        # end array

        with open(targetFile, 'w') as tf:
            tf.write(charArray)

if __name__ == "__main__":
    sourceFile = sys.argv[1]
    targetFile = sys.argv[2]

    arrayify(sourceFile, targetFile)

```
> 0 votes

---
Tags: esp8266, string
---


# Question
Title: Perform Volume Control on arduino speaker
I am following this guide to produce tones with the arduino: https://www.arduino.cc/en/Tutorial/BuiltInExamples/toneMelody

This uses the `tone()` builtin function. The connections is that one pin of the speaker got to one digital pin of the arduino, while the other goes to ground.

Is there a way to perform volume control (perhaps with a potentiometer) on this setup? What worries me is that this is digital information (PWM) that goes to the speaker, and not an analog signal that can be adjusted.

# Answer
There is a library from LixieLabs that implements an audio-based PWM at super high frequencies that allows you to change the tone volume without additional hardware.
> 3 votes

# Answer
The `tone()` function generates a 50% duty cycle square wave using a timer and interrupts. 50% duty cycle is basically full volume.

It's possible to reduce the volume by reducing the duty cycle, but the `tone()` function does not support it. It is of course possible to change the software PWM generation to change the duty cycle (I wouldn't know how, so don't ask me), but I'll leave that as an academic exersize for you to experiment with should you wish.

An alternative is to do it in hardware. You can use an op-amp as buffer (or speaker driver) and a couple of resistors (or a potentiometer) as an "attenuator" before it to change the voltate of the signal going to the op-amp.

You need the op-amp as a buffer because the speaker will mess with the potentiometer otherwise.
> 2 votes

---
Tags: pwm, audio, potentiometer, sound, speaker
---


title: Send HEX number over serial

text:
# Question
Title: Send HEX number over serial
I have a RS232 device that I am able to communicate with using RealTerm on a windows PC.

The device is expecting a hex string like `AA BB 03 01 03 EE`

---

How would I send the equivalent string from an arduino? (I feel confident the arduino is wired correctly since I can see incoming uart data)

Things I have tried

```
void setup() {
  Serial.begin(9600); // opens serial port, sets data rate to 9600 bps
}

void loop() {
      Serial.println('AA BB 03 01 01 EE', "OCT");
      delay(3000);
      Serial.println('0xAA 0xBB 0x03 0x01 0x01 0xEE', "DEC");
      delay(3000);
      Serial.println('AA BB 03 01 01 EE', "DEC");
      delay(3000);
      Serial.println('AA BB 03 01 01 EE', "DEC");
      delay(3000);
      Serial.println('AA BB 03 01 01 EE', "DEC");
      delay(3000);
      Serial.print('0xAA 0xBB 0x03 0x01 0x01 0xEE', "DEC");
      delay(3000);
      Serial.print('AA BB 03 01 01 EE', "DEC");
      delay(3000);
      Serial.print('AA BB 03 01 01 EE', "DEC");
      delay(3000);
      Serial.print('AA BB 03 01 01 EE', "DEC");
      delay(3000);
      Serial.println('AA BB 03 01 01 EE', HEX);
      delay(3000);
      Serial.println('0xAA 0xBB 0x03 0x01 0x01 0xEE', HEX);
      delay(3000);
      Serial.println('0xAA 0xBB 0x03 0x01 0x01 0xEE');
      delay(3000);
      Serial.println('0xAA 0xBB 0x03 0x01 0x01 0xEE', HEX);
      delay(3000);
      Serial.write('AA BB 03 01 01 EE');
      delay(3000);
      Serial.write('0xAA 0xBB 0x03 0x01 0x01 0xEE');
      delay(3000);
}

```

I've also tried using double quotes as mentioned in the comments

```
     Serial.write("AA BB 03 01 01 EE");
     delay(3000);

     Serial.write("0xAA 0xBB 0x03 0x01 0x01 0xEE");
     delay(3000);

     Serial.write("101010101011101100000011000000010000000111101110");
     delay(2000);

```

Additionally I've tried writing the serial one line at a time

```
  Serial.write(0xaa); // AA
  Serial.write(0xbb); // BB
  Serial.write(0x03); // 03
  Serial.write(0x01); // 01
  Serial.write(0x01); // 01
  Serial.write(0xee); // EE
  Serial.write(0x0d); // \r
  Serial.write(0x0a); // \n
  delay(3000);

```

Additional Information

# Answer
> 3 votes
As noticed by jsotola in a comment, your device doesn't seem to be expecting HEX at all, but rather plain binary. `Serial.print()` is not appropriate, as it is designed for sending ASCII text. For binary data, you should prefer `Serial.write()`. More specifically, for sending arbitrary binary data, the proper method is

```
size_t Print::write(const uint8_t *buffer, size_t size)

```

Applying this to your example gives:

```
const size_t packet_length = 6;
uint8_t packet[packet_length] = {0xaa, 0xbb, 0x03, 0x01, 0x03, 0xee};
Serial.write(packet, packet_length);

```

# Answer
> 0 votes
if device expects actual numbers, then it does not receive them in hex format or decimal, but in binary. in which case you would need an array of numbers and then go with them using for loop (or purpouse made function.

```
byte sequence[]={0xAA, 0xBB, 0x03, 0x01, 0x01, 0xEE};
for(byte i=0; i<sizeof(sequence);i++) Serial.write(sequence[i]);

```

if you have to send it as a HEX, then its most likely a case of hex representation and you can use printf for that

```
Serial.printf("0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X", 0xAA, 0xBB, 0x03, 0x01, 0x01, 0xEE);

```

Another think is that you should be careful using `println` when communicating with other devices. `println` ads extra character (number) for new line, after the data you wish to send. if you only want to send data you wish to send, then use `print` instead

Edit: Thanks for the note from Edgar Bonet, I was warned that printf is still not a standard instruction outside of the ESP core. Its well worth adding it up by yourself. Look for a guide on arduino playground.

---
Tags: uart, hex
---


# Question
Title: How to make better looking webpages on an Arduino webserver?
I have a Teensy 4.1 with ethernet, but I have other networked MCUs like a D1 mini, various ESP8266s and Arduino ethernet shields.

My question is: how I can make better looking web pages on these devices, where having a filesystem is limited by memory, or which lack a filesystem.

Specifically, I would like to add SVG images; I'm interested in how to make things like background images. I understand HTML/CSS, and I can code in C, get my data, whatever, but I want to make the page look good too.

Here's an example of the issue as it relates to HTML being rendered; here is an HTML page:

```
<!DOCTYPE html>
<html>
  <head>
    <style>
      body {
           background-image: url(example.svg);
           }
    </style>
  </head>
  <body>
  </body>
</html>

```

Cool, well to write that in something an Arduino can render, you use print statements; you might write:

```
// listen for incoming clients
// forgoing all of server setup
EthernetClient client = server.available();
client.println("<!DOCTYPE html><head><style>");
client.println("body {background-image: url(example.svg);}");
client.println("</style></head><body></body></html>");

```

This won't work without a filesystem, or won't work as is.

Then, I tried inline SVG:

```
// listen for incoming clients
// forgoing all of server setup
EthernetClient client = server.available();
client.println("<!DOCTYPE html><head><style>");
client.println("body { ");
client.println("background-image: url("data:image/svg+xml;utf8,<svg>**Omited**</svg>);");
client.println("}");
client.println("</style></head><body></body></html>");

```

This works, sometimes, but seems to have limitations as well.

I'm just wondering how I can make great looking webpages with stylesheets on an Arduino, only using print statements, or not requiring a filesystem.

# Answer
Your method of embedding SVG seems unnecessarily complicated to me. You don't need to give a URL of anything. Below is valid for putting SVG onto a web page:

```
<!DOCTYPE html>
<html lang="en">
<head>
  <meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
  <title>Test</title>
</head>
<body>
<div style="position:absolute; z-index:-1;">
  <svg width="500" height="500">
    <rect x="5" y="5" width="450" height="450" fill="lightblue" stroke="black"></rect>
  </svg>
</div>
<p style="padding:10px;">
Hello, world
</body>
</html>

```

The "position:absolute" and the z-index styles put the SVG in a fixed position on the page (like a background image) and underneath anything else you might put there.
> 2 votes

# Answer
well, I still want to know more about writing great looking webpages on ardunio network devices.

I got my immediate issue sorted for now. html/css seems to have some issues I dont quite understand as they relate to print statements, and Im pretty sure the url attribute is what is getting me.

I found this great github project that encodes svg for css inline functions. https://yoksel.github.io/url-encoder/

I set up a basic web server example to simplify the code I was looking at. its weird, on html pages I have put full style sheets on one line and never had a problem. here, it wouldn't work until I broke the style sheet into multiple lines (even with the url encoded svg).

Here is my simpler example for a page with a background image:

```
#include <SPI.h>
#include <NativeEthernet.h>
void  pageWrite(EthernetClient client);
void listenClient(EthernetClient client);
byte mac[] = {
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
};
IPAddress ip(10, 1, 0, 177);
EthernetServer server(80);
void setup() {

  delay(5000);  //you want this delay. reason: tl;dr
  Serial.begin(9600);
  Ethernet.begin(mac, ip);

if (Ethernet.linkStatus() == LinkOFF) {
    Serial.println("Ethernet cable is not connected.");
  }
  // start the server
  server.begin();
  delay(100);
  Serial.print("server is at ");
  Serial.println(Ethernet.localIP());
} //end setup

void loop() {
      EthernetClient client = server.available();
listenClient(client);
}  //end loop
void listenClient(EthernetClient client){

   if (client) {
    boolean currentLineIsBlank = true;
    while (client.connected()) {
       if (client.available()) {
          char c = client.read();
       // Serial.write(c);   //tells about the client connection
        if (c == '\n' && currentLineIsBlank) {
          pageWrite(client);
          break;
        }
        if (c == '\n') {
          // you're starting a new line
          currentLineIsBlank = true;
        } else if (c != '\r') {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }
      }//end avail
    } //end conect
    // give the web browser time to receive the data
    delay(1);
    // close the connection:
    client.stop();
  } //end client
}//end listenClient()
void  pageWrite(EthernetClient client){
client.println("<!DOCTYPE html><html><head><style>");
client.println("body {");
client.println("background-image:");
client.println("url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 227.35277 156.29323' height='6.1532764in' width='8.9508963in' %3E%3Cpath style='fill:%23ff0000; stroke:%23ff0000; stroke-width:1.32300019;stroke-miterlimit:4; stroke-dasharray:none; stroke-opacity:1' d='m 12.000819,0.66145838 c -6.2819637,0 -11.33936062,5.05739692 -11.33936062,11.33936062 V 144.29249 c 0,6.28197 5.05739692,11.33936 11.33936062,11.33936 H 215.35224 c 6.28197,0 11.33885,-5.05739 11.33885,-11.33936 V 12.000819 c 0,-6.2819637 -5.05688,-11.33936062 -11.33885,-11.33936062 z M 18.932696,12.696383 H 205.5854 c 5.02557,0 9.07128,4.04571 9.07128,9.071282 v 77.03923 c 0,5.025575 -4.04571,9.071285 -9.07128,9.071285 H 18.932696 c -5.025572,0 -9.0712819,-4.04571 -9.0712819,-9.071285 v -77.03923 c 0,-5.025572 4.0457099,-9.071282 9.0712819,-9.071282 z' /%3E%3Cellipse style='fill:%23ffffff;fill-opacity:1; stroke:%23ff0000; stroke-width:1.32300007; stroke-miterlimit:4; stroke-dasharray:none; stroke-opacity:1' cx='21.16666' cy='130.59085' rx='10.583334' ry='9.0714283' /%3E%3Cellipse style='fill:%23ffffff; fill-opacity:1; stroke:%23ff0000; stroke-width:1.32300007; stroke-miterlimit:4; stroke-dasharray:none;stroke-opacity:1' cx='200.62982' cy='131.57361' rx='10.583334' ry='9.0714283' /%3E%3C/svg%3E%0A\");");
client.println("background-repeat: no-repeat;");
client.println(" }");
client.println(" </style></head><body ></body></html>");
    }

```
> 1 votes

# Answer
As I understand what you want to send is basically a big string(s) stored in memory. You can quite easily store it it in external memory. You can use FRAM which is non volatile with 32K x 8 modules available for less then $5.00. They will run (Read / Write) at I2C or SPI speeds, no delays for writing or reading. There are other memory types that will also do the job but this is simple and inexpensive.

I am currently doing that with a project I am working on. It is using an Arduino Nano with about 20K of messages and several of application / program data that I store. Flash will not contain the messages and the program, not enough room. The program data is created via sensors and a rotary switch. I load the data into the FRAM sometimes in sections depending on size with my loading code. I then go to my application code which retrieves the messages from the FRAM and displays them on the LCD and terminal.

There is a pointer table in a specific location in FRAM that is pointing to each message address, size etc. This allows messages and other data to change without changing the main code. The FRAM in my case is a plug in module. This approach although a bit convoluted works nicely and you do not have to have a file structure. You can if you want. I do not know if this will work for you but it does for me.
> 1 votes

# Answer
Gonna answer my own question again lol. I looked at spiffs, but it seemed to just be an esp thing.
anyhow, I realized that `<!DOCTYPE html>` probably wasn't the only doctype there is, and that svg would probably render just fine without html or css. which is true! I used `<!DOCTYPE svg>` and got rid of html and css, which means I didn't need to use some fancy inline css encoding, and could instead make much simpler println() statements, and still generate an accessible "webpage" written in only svg. I could probably clean up the svg too, I drew it in inkscape, which generates overly complicated svg data.

But the project works now.. in a basic sort of way anyway.

```
/*
An IoT Etch-A-Sketch
uses 2 rotory encoders to generate x,y data points
in a svg poly line.

*/
#include <SPI.h>
#include <NativeEthernet.h>
#include <SD.h>
File dataFile;

byte mac[] = {
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
};

IPAddress ip(10, 1, 0, 177);
EthernetServer server(80);
//Function defs
void rotors();
void rotorA(EthernetClient client);
void rotorB(EthernetClient client);
void resetImg();  //erase datalog.txt
void Abuton();
void Bbuton();
void listenClient(EthernetClient client);
void pageWrite(EthernetClient client);
void polyLineBegin(EthernetClient client);
void startPage(EthernetClient client);
void endPage(EthernetClient client);

//int potX = A0;
//int potY = A1;

int sensorValX = 0;
int sensorValY = 0;

int oldX = 0;
int oldY = 0;

/**Rotor Vars**/
// Rotary Encoder Input defintions
#define CLKA 2
#define DTA 3
#define SWA 4

#define CLKB 5
#define DTB 6
#define SWB 7

int Acounter = 0;
int Bcounter = 0;

int AcurrentStateCLK;
int BcurrentStateCLK;

int AlastStateCLK;
int BlastStateCLK;

unsigned long AlastButtonPress = 0; //butons on rotory encoders
unsigned long BlastButtonPress = 0;

void setup() {

  delay(10000);  //you want this delay. reason: tl;dr
  /** Set encoder pins as inputs **/
  pinMode(CLKA,INPUT);
  pinMode(DTA,INPUT);
  pinMode(SWA, INPUT_PULLUP);
  pinMode(CLKB,INPUT);
  pinMode(DTB,INPUT);
  pinMode(SWB, INPUT_PULLUP);

  // Read the initial state of CLK
  AlastStateCLK = digitalRead(CLKA);
  BlastStateCLK = digitalRead(CLKB);
  /***End Rotary Encoder vars****/

  Serial.begin(9600);

  Ethernet.begin(mac, ip);

if (Ethernet.linkStatus() == LinkOFF) {
    Serial.println("Ethernet cable is not connected.");
  }

  // start the server
  server.begin();
  delay(100);
  Serial.print("server is at ");
  Serial.println(Ethernet.localIP());
  Serial.print("Initializing SD card...");

  if (!SD.begin(BUILTIN_SDCARD)) {
    Serial.println("SD Card init failed!");
    while (1);
    }
/****SD CARD and Ethernet intialized*****/
//if data file (on SD Card) Doesn't exist, create it.
//if data file (on SD Card) does exist errase it and create a new one
  if (SD.exists("datalog.txt")) {
     Serial.println("datalog.txt exists: \n Removing it.");
     while(SD.remove("datalog.txt")!=1){
       Serial.println("Deleeting old file data");
       if (SD.remove("datalog.txt")==1){
          Serial.println ("old dataFile removed");
       }
     }
  } else {
    Serial.println("datalog.txt doesn't exist.");
         }

  // open a new file and immediately close it:
  Serial.println("Creating datalog.txt...");
  dataFile = SD.open("datalog.txt", FILE_WRITE);
  dataFile.close();

  // Check to see if the file exists:
  if (SD.exists("datalog.txt")) {
    Serial.println("datalog.txt exists.");
  } else {
    Serial.println("datalog.txt wasn't created.");
         }
} //end setup

void loop() {
 // listen for incoming clients
  EthernetClient client = server.available();
rotors();
listenClient(client);
}  //end loop
void listenClient(EthernetClient client){

   if (client) {
    boolean currentLineIsBlank = true;
    while (client.connected()) {
       if (client.available()) {
          char c = client.read();
       // Serial.write(c);   //tells about the client connection
        if (c == '\n' && currentLineIsBlank) {
          pageWrite(client);
          break;
        }
        if (c == '\n') {
          // you're starting a new line
          currentLineIsBlank = true;
        } else if (c != '\r') {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }
      }//end avail
    } //end conect
    // give the web browser time to receive the data
    delay(1);
    // close the connection:
    client.stop();
  } //end client
  }//end listener()

void pageWrite(EthernetClient client){
          startPage(client);
          polyLineBegin(client);
          endPage(client);
  }
void startPage(EthernetClient client){
     // doctype svg no need for html
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connection: close");  // the connection will be closed after completion of the response
          client.println("Refresh: 1");  // refresh the page automatically every 5 sec
          client.println();
          client.println("<!DOCTYPE svg>");
          client.println("<svg   xmlns='http://www.w3.org/2000/svg'  viewBox='0 0 227.35277 156.29323' height='6.1532764in' width='8.9508963in'><path  style='fill:#ff0000; stroke:#ff0000; stroke-width:1.32300019;stroke-miterlimit:4; stroke-dasharray:none; stroke-opacity:1' d='m 12.000819,0.66145838 c -6.2819637,0 -11.33936062,5.05739692 -11.33936062,11.33936062 V 144.29249 c 0,6.28197 5.05739692,11.33936 11.33936062,11.33936 H 215.35224 c 6.28197,0 11.33885,-5.05739 11.33885,-11.33936 V 12.000819 c 0,-6.2819637 -5.05688,-11.33936062 -11.33885,-11.33936062 z M 18.932696,12.696383 H 205.5854 c 5.02557,0 9.07128,4.04571 9.07128,9.071282 v 77.03923 c 0,5.025575 -4.04571,9.071285 -9.07128,9.071285 H 18.932696 c -5.025572,0 -9.0712819,-4.04571 -9.0712819,-9.071285 v -77.03923 c 0,-5.025572 4.0457099,-9.071282 9.0712819,-9.071282 z' /><ellipse style='fill:#ffffff;fill-opacity:1; stroke:#ff0000; stroke-width:1.32300007; stroke-miterlimit:4; stroke-dasharray:none; stroke-opacity:1' cx='21.16666'  cy='130.59085'  rx='10.583334' ry='9.0714283' /><ellipse  style='fill:#ffffff; fill-opacity:1; stroke:#ff0000; stroke-width:1.32300007; stroke-miterlimit:4; stroke-dasharray:none;stroke-opacity:1' cx='200.62982'   cy='131.57361' rx='10.583334' ry='9.0714283'/>");
          client.println("\n<polyline points='15,15");
   }
 void endPage(EthernetClient client){
  client.print("' \nfill='none' stroke='#ff0000'/></svg>");
   }
void polyLineBegin(EthernetClient client){
//read data points from SD card
    File dataFile = SD.open("datalog.txt");
  // if the file is available, read it:
  if (dataFile) {
    while (dataFile.available()) {
      //Serial.write(dataFile.read());
      client.write(dataFile.read());
    }
    dataFile.close();
  }
}

int rotorA(){ //X coords
  AcurrentStateCLK = digitalRead(CLKA);
  if (AcurrentStateCLK != AlastStateCLK  && AcurrentStateCLK == 1){
     if (digitalRead(DTA) != AcurrentStateCLK) {
      Acounter --;
      }else{
       Acounter ++;
       }
     }
// Remember last CLK state
  AlastStateCLK = AcurrentStateCLK;
Abuton(); //errase the data file if A button pressed.
//X limits
if(Acounter<=15){
  Acounter=15;
  }
if(Acounter>=215){
  Acounter=215;
  }
return Acounter;
  }//endA rotor

int rotorB(){ //Y coords
  BcurrentStateCLK = digitalRead(CLKB);
  if (BcurrentStateCLK != BlastStateCLK  && BcurrentStateCLK == 1){
    if (digitalRead(DTB) != BcurrentStateCLK) {
       Bcounter --;
       }else{
        Bcounter ++;
     }
    //Serial.println(Bcounter);
  }
  BlastStateCLK = BcurrentStateCLK;
Bbuton();
//Y limits
if(Bcounter<=15){
  Bcounter=15;
  }
if(Bcounter>=210){
  Bcounter=210;
  }
  return Bcounter;
  }//EndB rotor

void rotors(){
//read rotors and write x,y points to datalog.txt
 sensorValX=rotorA();
 sensorValY=rotorB();
String dataString = "";

if(sensorValX!=oldX || sensorValY!=oldY){
   dataString += ",";
   dataString += String(sensorValX);
   dataString += ", ";
   dataString += String(sensorValY);

   Serial.println(dataString);

   dataFile = SD.open("datalog.txt", FILE_WRITE);
    // if the file is available, write to it:
   if (dataFile) {
      dataFile.print(dataString);
      dataFile.close();
      //clear dataString
      dataString="";
      }else{
    // if the file isn't open, pop up an error:
    Serial.println("error opening datalog.txt");
  }
  dataFile.close();
  }else{
  ;
  }

 oldX=sensorValX;
 oldY=sensorValY;

}//end rotors
void resetImg(){
  //clear datapoints by errasing datafile.
  if (SD.exists("datalog.txt")) {
     Serial.println("Deleting data.");
     while(SD.remove("datalog.txt")!=1){
       Serial.println("Deleeting old file data");
       if (SD.remove("datalog.txt")==1){
          Serial.println ("old dataFile removed");
       }
     }
  } else {
    Serial.println("datalog.txt doesn't exist.");
         }

  // open a new file and immediately close it:
  Serial.println("Creating datalog.txt...");
  dataFile = SD.open("datalog.txt", FILE_WRITE);
  dataFile.close();

  // Check to see if the file exists:
  if (SD.exists("datalog.txt")) {
    Serial.println("New datalog.txt created.");
  } else {
    Serial.println("datalog.txt wasn't created.");
         }

  }//end resetImg

void Abuton(){ //X buton
    int AbtnState = digitalRead(SWA);
  //If we detect LOW signal, button is pressed
if (AbtnState == LOW) {
    if (millis() - AlastButtonPress > 500) {
      Serial.println("Resting image!");
      resetImg();
    }
  AlastButtonPress = millis();
  }
  } //end Abuton

void Bbuton(){ //Y buton
int BbtnState = digitalRead(SWB);
    if (BbtnState == LOW) {
    //if 50ms have passed since last LOW pulse, it means that the
    //button has been pressed, released and pressed again
    if (millis() - BlastButtonPress > 50) {
      Serial.println("Button B pressed!");
    }
    BlastButtonPress = millis();
  }
}

```
> 0 votes

# Answer
Here's an alternative way of doing things I like to use:

What I like to do, when working with Arduinos with a decent amount of memory like the SAMD21-based ones, is create a fully self-contained webpage, that is, a webpage that has all HTML, CSS and Javascript in the same file, and all bitmap and SVG images in-lined in that same file. In short, a webpage file that is *completely* self-contained.

I then gzip that file (which compresses it *a lot*), and then base64 encode the gzipped file. The base64-encoded page is then copy/pasted into the code / memory as a `const char*`.

When the page needs to be served, I base64-decode it, and then serve the gzipped version, which all browsers accept if you put `Content-Encoding: gzip` in the header.

I put an elaborate example on Github, maybe you can get some inspiration from that. The webpage in the example is 26.8 kB in size, and the base64-encoded, gzipped webpage string as put into the code comes in at a little under 7 kB.
> 0 votes

---
Tags: web-server, iot
---


# Question
Title: Code does not run when Arduino is powered by AC adapter
I'm trying to implement the circuit as shown with an Arduino Nano. The project runs fine when powered via the USB port of the Arduino. However, the code freezes when connected to an AC adapter. When switched back to power supply via USB, the code does not run and resetting the board has no effect. The board starts to work again only when the code is re-uploaded.

Tried the following to troubleshoot the issue with no success:

1. Changed the power supply
2. Tried with a blink sketch and an example code of U8glib
3. Eliminated the MOSFET's Q1 & Q2 to simplify further

The only other component in question seems to be the buck converter connected between the AC adapter and the Nano board, but it is rated for 5 V, 3 A and should not be of concern I believe. I appreciate your inputs.

I uploaded a blink sketch to the Nano. It works OK over the USB power, but it starts resetting randomly when connected to the power supply. I swapped the buck converter with an LDO and it seems to work flawlessly. The output of the buck converter reads about 5.18 V and according to the ATmega328p datasheet, it can accept up to 5.5 V.

Could the problem be associated with the switching frequency of the buck converter (the stated switching frequency is about 500 kHz).

P.S. I'm using the Nano clone. I'm not sure if it adheres to the original parameters as stated in the ATmega datasheet.

# Answer
> 0 votes
Is the buck converter properly filtered?

Many ebay/amazon supplies are done too cheaply. While LEDs will run from practicaly anything with at-least some sign of correct specs, combination of back converter trying to keep-up with changing current and compensate to achieve correct voltage, while voltage regulator is adjusting and as such changing the consumption characteristics... dependant on buck converters changes. MCU requirements for clean supply are lot greater them that of LEDs. Bunch of suitable capacitors after the buck converter, but before the arduino might do it. Hopefuly somebody better then me in that area might advice you bout capacitor values. mine rough guess would be 100nF of about 20V.

---
Tags: arduino-nano, power
---


# Question
Title: How to send an array of unknown size via I2C (from slave to master)?
When I try something like this, everything works.

Slave:

```
    # define DEFAULT_DATA_SIZE 256

    byte DATA[DEFAULT_DATA_SIZE];

    void requestEvent()
    {
      Wire.write( (byte*) DATA, sizeof(DATA));
    }

    void receiveEvent(int numBytes)
    {
      for (int i = 0; i < numBytes; i++) {
        DATA[i] = Wire.read();
      }
    }

```

Master:

```
    # define DEFAULT_DATA_SIZE 5

    void writeData(byte data[], int numBytes) {
      Wire.beginTransmission(I2C_SLAVE_ADDRESS);
      for (int i = 0; i < numBytes; i++)
      {
        Wire.write(data[i]);
      }
      Wire.endTransmission();
    }

    void readData() {
      byte data[DEFAULT_DATA_SIZE];
      Wire.requestFrom( I2C_SLAVE_ADDRESS, DEFAULT_DATA_SIZE );
      if ( Wire.available() == sizeof( data))
      {
        Wire.readBytes( (byte *) data, DEFAULT_DATA_SIZE);
      }
      Serial.print("Byte Array: ");
      for (int i = 0; i < DEFAULT_DATA_SIZE; i++ ) {
        Serial.print(data[i]);
        Serial.print(" ");
      }
      Serial.println();
    }

    byte data[5] = {0x1, 0x2, 0x3, 0x4, 0x5 };

    void setup()
    {
      Wire.begin();
      Serial.begin(9600);

      writeData(data, sizeof(data));
      delay(500);
      readData();
    }

    void loop() {

    }

```

But this only works when the master knows how long the array needs to be. If I set the value of `DEFAULT_DATA_SIZE` not to 5, but more, then I get a set of random numbers.

I tried to make the slave pass the length of the array first, and then the array itself. But for some reason it doesn't work and I also get random numbers.

Slave:

```
    #include <Wire.h>
    # define I2C_SLAVE_ADDRESS 12
    # define DEFAULT_DATA_SIZE 256

    byte DATA[DEFAULT_DATA_SIZE];
    int RECEIVED_NUMBYTES = 0;
    bool isNumBytesSended = false;

    void setup()
    {
      Wire.begin(I2C_SLAVE_ADDRESS);
      delay(1000);
      Wire.onRequest(requestEvent);
      Wire.onReceive(receiveEvent);
    }

    void loop()
    {
    }

    void requestEvent()
    {
      if (!isNumBytesSended) {
        isNumBytesSended = true;
        Wire.write(RECEIVED_NUMBYTES);
      }
      else {
        isNumBytesSended = false;
        Wire.write( (byte*) DATA, sizeof(DATA));
      }
    }

    void receiveEvent(int numBytes)
    {
      RECEIVED_NUMBYTES = numBytes;
      for (int i = 0; i < numBytes; i++) {
        DATA[i] = Wire.read();
      }
    }

```

Master:

```
    #include <Wire.h>
    # define I2C_SLAVE_ADDRESS 12
    # define DEFAULT_DATA_SIZE 10

    void writeData(byte data[], int numBytes) {
      Wire.beginTransmission(I2C_SLAVE_ADDRESS);
      for (int i = 0; i < numBytes; i++)
      {
        Wire.write(data[i]);
      }
      Wire.endTransmission();
    }

    void readData() {
      Wire.requestFrom( I2C_SLAVE_ADDRESS, 1 );
      int numBytes = Wire.read();
      Serial.println("numBytes: " + String(numBytes));

      byte data[numBytes];
      if ( Wire.available() == sizeof( data))
      {
        Wire.readBytes( (byte *) data, numBytes);
      }
      Serial.print("Byte Array: ");
      for (int i = 0; i < numBytes; i++ ) {
        Serial.print(data[i]);
        Serial.print(" ");
      }
      Serial.println();
    }

    byte data[5] = {0x1, 0x2, 0x3, 0x4, 0x5 };

    void setup()
    {
      Wire.begin();
      Serial.begin(9600);

      writeData(data, sizeof(data));
      delay(100);
      readData();
    }

    void loop() {

    }

```

Master outputs:

> 01:20:13.844 -\> numBytes: 5
> 01:20:13.878 -\> Byte Array: 11 8 212 8 22
> 01:21:51.222 -\> numBytes: 0
> 01:21:51.255 -\> Byte Array:
> 01:21:54.323 -\> numBytes: 5
> 01:21:54.323 -\> Byte Array: 11 8 212 8 22
> 01:22:01.682 -\> numBytes: 0
> 01:22:01.717 -\> Byte Array:
> 01:22:04.280 -\> numBytes: 5
> 01:22:04.314 -\> Byte Array: 11 8 212 8 22
> 01:22:06.879 -\> numBytes: 0
> 01:22:06.912 -\> Byte Array:
> 01:22:10.386 -\> numBytes: 5
> 01:22:10.420 -\> Byte Array: 11 8 212 8 22

Please tell me the best way to solve this problem. Maybe transfer all values one byte at a time, and put a special delimiter between the beginning of new data?

# Answer
> 1 votes
yes, the idea of sending one byte at a time and specifying the length of the array worked. I'm surprised that I didn't do that sooner :)

SLAVE:

```
#include <Wire.h>
# define I2C_SLAVE_ADDRESS 12
# define DEFAULT_DATA_SIZE 256

byte DATA[DEFAULT_DATA_SIZE];
int pointer = 0;

void setup()
{
  Wire.begin(I2C_SLAVE_ADDRESS);
  delay(1000);
  Wire.onRequest(requestEvent);
  Wire.onReceive(receiveEvent);
}

void loop()
{
}

void requestEvent()
{
  if (pointer > DATA[0]) {
    Wire.write(0);
  }
  else {
    Wire.write(DATA[pointer++]);
  }
}

void receiveEvent(int numBytes)
{
  DATA[0] = numBytes;
  for (int i = 1; i <= numBytes; i++) {
    DATA[i] = Wire.read();
  }
  pointer = 0;
}

```

MASTER:

```
#include <Wire.h>
# define I2C_SLAVE_ADDRESS 12

void writeData(byte data[], int numBytes) {
  Wire.beginTransmission(I2C_SLAVE_ADDRESS);
  for (int i = 0; i < numBytes; i++)
  {
    Wire.write(data[i]);
  }
  Wire.endTransmission();
}

void readData() {
  Wire.requestFrom( I2C_SLAVE_ADDRESS, 1 );
  int numBytes = Wire.read();
  Serial.println("numBytes: " + String(numBytes));

  byte data[numBytes];

  for (int i = 0; i < numBytes; i++) {
    Wire.requestFrom( I2C_SLAVE_ADDRESS, 1 );
    data[i] = Wire.read();
  }
  Serial.print("Byte Array: ");
  for (int i = 0; i < numBytes; i++ ) {
    Serial.print(data[i]);
    Serial.print(" ");
  }
  Serial.println();
}

byte data[8] = {0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8 };

void setup()
{
  Wire.begin();
  Serial.begin(9600);

  writeData(data, sizeof(data));
  delay(100);
  readData();
}

void loop() {

}

```

---
Tags: i2c
---


# Question
Title: Powering Arduino Mega 2560 from a Raspberry Pi Usb
I have a Raspberry Pi B+ running 7x24. I have to connect an Arduino Mega 2560 to its USB. The Arduino has only one nRF24L01-PA-LNA powered from its 3V3. Can I power the Arduino from the Pi's USB?

# Answer
If you are powering your RPi from power supply 5V/2A at least there should be no problem. USB hub on the RPi should not give more than 500mA to power Arduino. Also there is a fuse on Arduino's board to prevent any damage from USB power.

Check both Arduino and RPi schematics for more details about modules used there:
> 2 votes

# Answer
raspberry pi can power ur mega board normally,but the 3v3 in the mega board is not stable and has noise,so it is better to use 3v3 supply source for ur NRF the simplest to use is just hooking a piece of 1117 to 5v of ur mega board
> 1 votes

# Answer
Yeah, as the others have mentioned you can power the Arduino form the raspberry pi's power supply, but you cannot transit data from the raspberry to the Arduino without a third party software.
> 0 votes

---
Tags: arduino-mega, nrf24l01+, raspberrypi
---


# Question
Title: Pro Micro COM port disappeared after upload
I uploaded a sketch to my Pro Micro and it stopped showing in serial ports. Other Arduinos show up just fine.

I've tried to detect serial devices using pyserial and it's also not seeing anything. I've tried to reset the board by connecting the reset pin to ground twice in quick succession but it's not doing anything.

The board might be broken, but it seems unlikely to me as it's not connected to anything high powered.

The sketch I uploaded does use serial, but that hasn't been a problem before.

Any ideas on how to recover the board?

# Answer
The Pro Micro uses a single processor (ATmega32U4) unlike some of the other Arduinos which have a separate processor for USB communications.

When reset, it will appear as a USB device for a couple of seconds, and then if the sketch does not use Serial, or uses it inappropriately, it could stop responding. For example, if the code went into a loop.

It is highly unlikely that the board just "broke". I suggest keeping the processor in Reset (tie Reset to Ground) while you compile a new sketch, and then release Reset when it tells you it is starting to upload.

You haven't posted your code, but it quite possibly is the problem. For example, you might have disabled interrupts.
> 0 votes

---
Tags: serial
---


# Question
Title: What's the difference between CloudTemperature, CloudTemperatureSensor and Float data types?
I have a SHT30 sensor for Wemos and I am learning to use Arduino IOT Cloud.

I use **float** data type for my `temperature` variable but I see two more data types:

**CloudTemperature**

**CloudTemperatureSensor**

What are the differences? Shouldn't use **float**?

# Answer
From the technical reference for the Arduino Cloud on arduino.cc:

> For your convenience, IoT Cloud provides specialized types which are just wrappers around basic types but declare the variable semantics more explicitly. This enables smarter integrations with third-party services (such as Alexa) and better visualization of widgets in dashboards.
>
> You can use them just like a normal variable of the wrapped type, since they support assignment and comparison operators.

These types are actually wrapper classes, which add some functionality to better integrate in cloud services. You can use these just as the normal data types.

---

You can even look at how they are defined. Let's look at `CloudTemperature` for example. All the files can be found in the ArduinoIoTCloud repo on github.

The types are defined in the PropertyContainer.h file:

```
...
#include "types/CloudFloat.h"
...
typedef CloudFloat CloudTemperature;
...

```

So `CloudTemperature` is actually just `CloudFloat`, which is included from the corresponding header file. When we look at the CloudFloat.h file we find:

```
class CloudFloat : public Property {
  protected:
    float _value,
          _cloud_value;
...

```

So internally `CloudFloat` is just a float value with added functionality. And you can use it like any other float, since below that part that I've shown here all the operators (like `/`, `*`, `+`, ...) are overwritten (so the class knows what to do with these operators).

`CloudTemperatureSensor` is found at CloudTemperatureSensor.h and inherits from `CloudFloat` so works basically the same way (it only overwrites the assignment operator; the rest is the same as `CloudFloat`).

---

> Shouldn't use float?

I haven't tried that myself. But from the documentation it sounds like there is no reason to not use the specialized types, since they provide the same functionality and more.
> 2 votes

---
Tags: temperature-sensor, variables, data-type, temperature, arduino-iot-cloud
---


# Question
Title: Arduino PRO Mini - The pads [was "jumpers"] on the back and Low Power Consumption
I've noticed that on the back of an Arduino PRO mini are two Jumpers next to the `A4` and `A5` pins, marked with red in the following :

Looking at the leads one seems to be a bypass for the POWER Led and the other a bypass for the regulator, but not sure.

Further, the schematic reveals just one Jumper `SJ1` :

https://cdn.sparkfun.com/datasheets/Dev/Arduino/Boards/Arduino-Pro-Mini-v14.pdf

So, my questions are :

1. Why are there two physical Jumpers on the board ?
2. Are these two jumpers actually just one : `SJ1` ?
3. And if so how to connect them in order to enable `Power isolation` ?

# Answer
> 5 votes
Both responses are correct but be mindful that this is a SparkFun feature. An Arduino Pro Mini from China won't necessarily have the `SJ1` pad.

1) Like Gerben said, the pads on the underside of the board are for I2C pull-up resistors.

2) Like David said, `SJ1` is on the top of the board next to the `GND` and `RST` pins. (It looks like a small solder blob.)

3) To isolate the regulator from `VCC`, remove the solder blob on the top of the board with a sucker or solder wick.

The Sparkfun schematic shows all of these elements: https://cdn.sparkfun.com/datasheets/Dev/Arduino/Boards/Arduino-Pro-Mini-v14.pdf

# Answer
> 1 votes
I think those aren't jumpers, but pads to place two pull-up resistors for I2C.

It seems the eagle files Sparkfun shares aren't the same as the board in the picture.

But you don't need to worry about this. If the RAW pin is not connected the MIC5205 regulator uses only 0.01μA according to the datasheet.

# Answer
> 1 votes
These pads are not jumper SJ1. On the front of the board just beneath the GND pad there is a blob of solder. This is SJ1 (I believe - I am writing from memory, I do not have a Pro Mini sitting on my desk at the minute) and removing the solder blob will disconnect the LED and output of the regulator from Vcc.

# Answer
> 1 votes
You can look up the location of SJ1 in the Eagle project files that are provided by Sparkfun). For example, you can import them into KiCad (Free and Open Source), which opens a PCB and a Schematic editor.

To locate SJ1 you can simply click on it in the Schematic editor such that it's highlighted in the PBC editor, as well. For better overview, you may want to hide all the layers besides the foreground one (e.g. 'F.Cu') and click View/Zoom-to-Fit:

-\> That means SJ1 is located on the front of the board, right of pin 9 (ground), i.e. it's highlighted in a lighter red. For comparison, I included an image (Sparkfun, CC BY 2.0) of the front, where you can see that SJ1 is marked by a white rectangle (painted on the board) and that it's closed, by default by a solder blob, which can be de-soldered (e.g. using solder wick and a bit of flux).

---

NB: To enable power isolation (i.e. such that the MCU can be directly powered without also powering the power-on LED and one side of the on-board LDO, e.g. in order to save power), you have to open SJ1.

---

Thus, the pads on the back of the board, you marked in an image you included in the question, are something different. In KiCad you can look them up as well: that means switch to the back layer (e.g. 'B.Cu') and click on the pads such that the related parts are highlighted in the schematic editor:

---
Tags: power, arduino-pro-mini
---


# Question
Title: Arduino Serial to USB=>serial data issue
I am using Mega 2560 to receive serial data from another device but the data appears on the serial terminal are strange characters. then i connected my USB to serial cable (HL-340) to the device and tried in serial terminal(Termite), data is landing fine. Replaced Arduino with another one since I believed there could be a problem, but the problem persisted. for further investigation i have connected my Arduino (Mega-2560) to my serial(USB-\>Serial) cable directly to receive data on the terminal but strangely even this is showing the wrong data (Arduino terminal is displaying the wright data but the data appears on the other terminal is wrong) sendind "c" receiving "N"... what could be the reason for this..its a simple code to print character on the screen. Thx

# Answer
> 3 votes
You need to be careful. Normal devices that have a "Serial" interface actually have an RS232 interface. While the data transmission scheme is similar with the "Serial" interface on the Uno/Mega (UART on TTL logic), RS232 has totally different voltage levels (up to -15 to +15V), which can kill your Arduino.

To connect an RS232 device to an Arduino you need a level converter (to convert between the RS232 levels and the TTL (Transistor Transistor Logic) level of the Arduino. The chip MAX232 is typically used for this. There are many resources about that on the web and even ready to use modules, which are equipped with a MAX232 and a RS232/Serial plug.

---
Tags: serial, arduino-mega, terminal
---


# Question
Title: Checking if Arduino board works or is damaged
I have an Arduino Uno and Mega, but when I connect them to a computer with the USB they came with, there is no green light near the reset button that illuminates.

On the Uno board the pin 13 continuously flashes with red light while on the Mega board the R17 and R18 both illuminate red light but no flashing.

How do I know if the boards work or are damaged?

# Answer
Did you try to connect to the computer and upload a blank sketch or a blink sketch... If the program complies and uploads successfully it is alive. But you will have to check IO, ADC and other features separately.
> 2 votes

---
Tags: arduino-uno, arduino-mega
---


# Question
Title: Updating ESP32 firmware from another ESP32 over USB, similar to how esptool.py works
Is there a way to update the firmware on one ESP32 from another ESP32 over USB, similar to how firmware can be updated using esptool.py?

This would essentially be like a port of whatever magic esptool.py uses over USB to update an ESP32, but instead of running through Python it would be an Arduino C++ sketch and would read the firmware to write to the other ESP32 from SPIFFS.

# Answer
> 1 votes
You can use the SD card to update the firmware. Here is the example code

# Answer
> 0 votes
The esp32 can update itself. To store and apply the updated sketch's binary it uses the Update library bundled with the ESP32 Arduino boards support package.

Then there are libraries for different ways of transporting the binary over network:

* ArduinoOTA for upload from the Arduino IDE
* HTTPUpdate to download the binary from a web server
* HTTPUpdateServer to upload the binary to ESP32 over a web page

The keyword is "OTA update" as "over the air update" even it is possible to transport the update over cable too.

---
Tags: esp32
---


title: Novice learning Serial.readString()

text:
# Question
Title: Novice learning Serial.readString()
New to Arduino, getting into String variables and reading them from serial monitor. Basically what I'm trying to do is have the user input either red, green, yellow. Whichever String they enter the LED comes on.

What is happening seems to be that the if statements are not true and are never entered thus not LEDs come on. I do have a serial.Println(myColor) at the end which displays myColor as the user has inputted into serial monitor. I just don't understand why the if statements are not firing. its really weird.

```
String msg="What LED do you want to turn on?";
String myColor;
int redPin = 12;
int greenPin = 13;
int yellowPin = 8;

void setup(){
Serial.begin(9600);
pinMode(redPin, OUTPUT);
pinMode(greenPin, OUTPUT);
pinMode(yellowPin, OUTPUT);
}

void loop(){
    //LED ColorDEmo

    Serial.println(msg);                //print the question to serial monitor
    while(Serial.available() == 0){     //while we wait do nothing till data is available

    }
    myColor = Serial.readString();      // set myColor to serial value

    if (myColor == "red"){              // if the value is red
        Serial.println("In red");
        turnOffLEDS();                  // turn off all LEDS
        digitalWrite(redPin, HIGH);     // turn on red lED
    }

    if (myColor == "green"){            // if the value is green
        Serial.println("In green");
        turnOffLEDS();                  // turn off all LEDS
        digitalWrite(greenPin, HIGH);   // turn on green LED
    }

    if (myColor == "yellow"){           // if the value is yellow
        Serial.println("In yellow");
        turnOffLEDS();                  // turn off all LEDS
        digitalWrite(yellowPin, HIGH);  // turn on yellow LED
    }
    Serial.println(myColor);            // print myColor

}

// turns all LEDS off
void turnOffLEDS(){
    digitalWrite(yellowPin, LOW);
    digitalWrite(greenPin, LOW);
    digitalWrite(redPin, LOW);
}

```

# Answer
Avoiding String objects (back to the basics) often makes life easier. Simply check if the answer contains one of the characters 'd' 'g' 'y'

Or (and) simplify your *protocol* to only send one character.

BTW:You might notice a delay in readString, waiting for a multi-character input to finish, because Serial.available() is true already after the first character of an input, and readString terminates only if it times out
> 1 votes

# Answer
thank you @jsotola

throught he debugging you mentioned i was able to learn that the '\n' was added to the end of the string. Instead of using `Serial.readString()` I used `Serial.readStringUntil('\n');`

this would check for a delimiter character '\n' then stop. Thus, my myColor variable would be red instead of red'\n'
> 0 votes

---
Tags: serial, c++, string, serial-data
---


# Question
Title: Gyro reading of MPU6050 drifts too much on fast changes only
I am trying to write a simple sketch for the MPU6050.

The problem is that the sensor is pretty much solid when stationary or changing the angle steadily at slow to mid angular velocities but if I try to change the angle too fast there's a huge drift in the readings by pretty much tens of degrees in either direction as shown in the below images from the serial plotter.

On slow to mid changes in the pitch angle the gyro is tracking the accelerometer pitch almost identically (it drifts a little over time but it's normal and acceptable for the complementary filter).

On fast changes however the pitch drifts instantly by tens of degrees from the accelerometer. The huge drift makes the complementary filter pretty much useless in correcting the output

It's my first try with the sensor so I don't have any experience with its parameters. But the problem seems to be in the lines of integrating the new angular velocities in roll and pitch.

* I got lazy and used the default sensitivity scale factors; does this have anything to do with this behaviour?
* The dt measured for the Arduino is 20 ms between readings; is this too slow for the fast changes or something?
* The datasheet also mentioned a programmable output range. Does this need to be programmed for more bandwidth and accurate results?

## EDIT:

I tried to read a bit about the sensitivity scale factor. It seemed that increasing the angular velocity beyond 250 degrees per second is not measured when selecting the default configuration.

After some testing I realized that 1000 deg/s is a good configuration for me; the drift certainly is much better but still not what I hoped for. It still drifts by +- 10 degrees in two or three seconds of moving it around.

## Slow to Mid changes output:

## Fast changes output:

```
#include <Wire.h>
#define CAL_AVERAGE 2000

const int MPU = 0x68; //I2C address of MPU6050
const float alpha = 0.95;

double ax, ay, az;
double gx, gy, gz;

//float accAngleX, accAngleY, accAngleZ;
//float gyroAgnleX, gyroAngleY, gyroAngleZ;

double accErrorX, accErrorY, accErrorZ;
double gyroErrorx, gyroErrorY, gyroErrorZ;

double accRoll, accPitch;
double gyroRoll, gyroPitch, gyroYaw;

double roll, pitch, yaw;

double dt, currentTime, previousTime;

void setup(){
  previousTime = 0;

  Serial.begin(115200);
  Wire.begin();     //init the communication

  //reset the mpu
  Wire.beginTransmission(MPU);
  Wire.write(0x6B);
  Wire.write(0x00);
  Wire.endTransmission(true);

  //calibrate here
  calculateError();
}

void loop(){
  readAcc();
  readGyro();

  //get roll and pitch of accelerometer
  accRoll = atan2(ay, az) * 180 / PI;
  accPitch = atan2(ax, az) * 180 / PI;

  currentTime = millis();
  //set gyro roll and pitch for accelerometer roll and pitch on first reading only
  if (previousTime != 0) {
    //get roll, pitch and yaw of gyro
    dt = currentTime - previousTime;
    dt /= 1000;
    gyroRoll += gx * dt;
    gyroPitch += -gy * dt;
    gyroYaw += gz * dt;
  } else {
    gyroRoll = accRoll;
    gyroPitch = accPitch;
    gyroYaw = 0;
  }

  previousTime =  currentTime;

  roll = alpha*gyroRoll + (1 - alpha)*accRoll;
  pitch = alpha*gyroPitch + (1 - alpha)*accPitch;
  yaw = gyroYaw;

  //finally print the values collected
  printData();
}

void readAcc(){
  //first read accelerometer data
  Wire.beginTransmission(MPU);
  Wire.write(0x3B);
  Wire.endTransmission(false);
  Wire.requestFrom(MPU, 6, true);

  //accelerometer raw data
  ax = ( (Wire.read() << 8) | Wire.read() ) / 16384.0;
  ay = ( (Wire.read() << 8) | Wire.read() ) / 16384.0;
  az = ( (Wire.read() << 8) | Wire.read() ) / 16384.0;

  ax -= accErrorX;
  ay -= accErrorY;
  az -= accErrorZ;
}

void readGyro(){
  //second read gyro
  Wire.beginTransmission(MPU);
  Wire.write(0x43);
  Wire.endTransmission(false);
  Wire.requestFrom(MPU, 6, true);

  //gyro raw data
  gx = ( (Wire.read() << 8) | Wire.read() ) / 131.0;
  gy = ( (Wire.read() << 8) | Wire.read() ) / 131.0;
  gz = ( (Wire.read() << 8) | Wire.read() ) / 131.0;

  gx -= gyroErrorx;
  gy -= gyroErrorY;
  gz -= gyroErrorZ;
}

void calculateError(){
  float axErr = 0, ayErr = 0, azErr = 0;
  float gxErr = 0, gyErr = 0, gzErr = 0;

  for (int i = 0; i < CAL_AVERAGE; i++) {
    readAcc();
    az = az - 1;

    axErr += ax;
    ayErr += ay;
    azErr += az;

    readGyro();

    gxErr += gx;
    gyErr += gy;
    gzErr += gz;
  }

  accErrorX = axErr/CAL_AVERAGE;
  accErrorY = ayErr/CAL_AVERAGE;
  accErrorZ = azErr/CAL_AVERAGE;

  gyroErrorx = gxErr/CAL_AVERAGE;
  gyroErrorY = gyErr/CAL_AVERAGE;
  gyroErrorZ = gzErr/CAL_AVERAGE;
}

void printData() {
  Serial.print(ax);
  Serial.print(",     ");
  Serial.print(ay);
  Serial.print(",     ");
  Serial.print(az);

  Serial.print(",               ");

  Serial.print(gx);
  Serial.print(",     ");
  Serial.print(gy);
  Serial.print(",     ");
  Serial.print(gz);

  Serial.print(",               ");

  Serial.print(accPitch);
  Serial.print(",     ");
  Serial.print(accRoll);

  Serial.print(",               ");

  Serial.print(gyroPitch);
  Serial.print(",     ");
  Serial.print(gyroRoll);
  Serial.print(",     ");
  Serial.print(gyroYaw);

  Serial.print(",               ");

  Serial.print(pitch);
  Serial.print(",     ");
  Serial.print(roll);
  Serial.print(",     ");
  Serial.print(yaw);

  Serial.print(",     ");
  Serial.println(dt);
}

```

# Answer
In his answer, st2000 recommends you use quaternions, rather than Euler angles, for tracking the orientation of your vehicle. I will give the exact same recommendation, but for a different reason: the formulas you use, namely

```
gyroRoll += gx * dt;
gyroPitch += -gy * dt;
gyroYaw += gz * dt;

```

are just plain wrong. They are correct if rotations only ever happen along a single axis. They are also “kinda good” (correct as a first-order approximation) if the angles involved are very small. But in the general case, they are wrong. A easy way to convince yourself of this fact is to notice that the final (yaw, pitch, roll) being the sum of many small contributions, they do not depend on the *order* in which these contributions were added. In other words, these formulas imply that the composition of rotations is commutative, which I hope you know is not the case.

The only reasonable ways of composing many rotations (which is what this attitude-tracking code tries to do) are rotation matrices and quaternions, the latter being more efficient.

Now, a few remarks:

1. You should not track (`gyroRoll`, `gyroPitch` and `gyroYaw`) independently from (`roll`, `pitch`, `yaw`), otherwise your complementary filter becomes inefficient at canceling gyro drift. You should instead merge those variable into a single triplet.
2. The line

```
( (Wire.read() << 8) | Wire.read() ) / 16384.0;

```

gets you the two bytes from the MPU in an unspecified order. They may be in the right order with this particular version of this particular compiler when run with this particular set of options, but you should not count on this order being reliable. You should instead read the two bytes in two separate statements.
3. If you do not care about the yaw, you may just track the gravity vector instead of the full attitude. This should save you the calls to `atan2()` and possibly simplify the math further. You may not even need the quaternions after all.
> 2 votes

# Answer
Consider what might happen if the code or hardware dead reckoning capabilities were too slow to accurately sample short events. Such as a sudden stop. Robbed of the opportunity to integrate a fast deceleration event, the code and hardware might continue to report motion.

To speed up code execution, consider switching from trigonometry based calculations to quaternion calculations. In general this replaces time consuming repetitive summation algorithms with simple math calculations more suitable for embedded processors.

To speed up the hardware, consider an Arduino platform with a faster processor.

Also consider more creative solutions suitable for your application:

* If angular momentum is more important than linear motion sample the accelerometer only every other time through your main loop.
* Or, if motion is totally random, and the device is on Earth, consider zero-calibrating the gyroscope when there is no movement perceived by the accelerometer. Specifically, when there is a 9.8m/s\*s vector sensed by the accelerometer and the pitch, roll and yaw of the accelerometer is not changing.
> 1 votes

---
Tags: arduino-uno, mpu6050, gyroscope, imu
---


# Question
Title: Problem uploading Arduino sketch on ESP8266-12e
I have a new Mac OS Sierra installed. I just installed the Arduino IDE and the serial drivers for Mac OS X to make the serial USB port available for esp8266 device

When I try to flash the device through the IDE I have these errors:

```
Arduino:1.8.3 (Mac OS X), Scheda:"NodeMCU 1.0 (ESP-12E Module), 80 MHz, 115200, 4M (3M SPIFFS)"

Archiving built core (caching) in: /var/folders/vz/qxry2ffs3rnd2xtd557pgcf00000gp/T/arduino_cache_169716/core/core_esp8266_esp8266_nodemcuv2_CpuFrequency_80,UploadSpeed_115200,FlashSize_4M3M_244c37a477ed4ef8a63952f7a6e6a50b.a
Lo sketch usa 222149 byte (21%) dello spazio disponibile per i programmi. Il massimo è 1044464 byte.
Le variabili globali usano 31524 byte (38%) di memoria dinamica, lasciando altri 50396 byte liberi per le variabili locali. Il massimo è 81920 byte.
error: failed reading byte
warning: espcomm_send_command: cant receive slip payload data
error: unslip sequence wrong
warning: espcomm_send_command: can't receive command response header
warning: espcomm_sync failed
error: espcomm_open failed
error: espcomm_upload_mem failed
error: espcomm_upload_mem failed

```

What can I do?

# Answer
> 0 votes
I installed another version of the driver from silabs' website and now it's working.

# Answer
> 1 votes
**3.x version of ESP8266 libraries**

If you're using the most updated version of the ESP8266 "NodeMCU 1.0 (ESP-12E Module)" board then all you need to do is update your Silabs library.

**2.x version of ESP8266 libraries**

If you're using a 2.x version of the ESP8266 "NodeMCU 1.0 (ESP-12E Module)" board, it is more involved. It comes with a packaged version of pyserial which resolves the wrong versions of the IOKit and CoreFoundation libraries. You will need to edit the pyserial script for your board version manually following the instructions here: https://forum.arduino.cc/t/pyserial-and-esptools-directory-error/671804/5.

An alternative is use the Windows version of the flashing tool provided by Espressif by running it through a Windows emulator or VM. You can find instructions for that here: https://blog.squix.org/2015/05/esp8266-flashing-nodemcu-v10-on-mac-os.html.

---
Tags: esp8266, mac-os
---


# Question
Title: POST request (HTTPClient) with ESP8266 not working on localhost (http code = -1)
I've been looking around for a solution, but couldn't manage to find one. I'm looking to send a post request from an ESP8266 on a local API. Here is my code :

```
#include <ESP8266WiFi.h>
#include <ESP8266HTTPClient.h>
#include <WiFiClient.h>

String ssid = "HUAWEI P30 lite";
String password = "testazerty";
String serverName = "http://192.168.56.1:3030/drink/voltron";

void setup() {
  Serial.begin(115200);
  WiFi.begin(ssid, password);
  Serial.println("Connecting");
  while(WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to WiFi network with IP Address: ");
  Serial.println(WiFi.localIP());
}

void loop() {

    if(WiFi.status()== WL_CONNECTED){
      WiFiClient client;
      HTTPClient http;

      http.begin(client, serverName);

      http.addHeader("Content-Type", "application/json");
      int httpResponseCode = http.POST("{\"city\":\"toronto\"}");

      Serial.print("HTTP Response code: ");
      Serial.println(httpResponseCode);

      http.end();
  }
}

```

Both my computer and ESP8266 are connected to my phone network (HUAWEI).

192.168.56.1 is the IP of my computer.

API is running, and I can successfully make the request from postman (see image below).

It always return -1 as http code. I activated debug level HTTP\_CLIENT, here is what I have on the serial monitor :

```
11:07:41.645 -> SDK:2.2.2-dev(38a443e)/Core:3.0.2=30002000/lwIP:STABLE-2_1_2_RELEASE/glue:1.2-48-g7421258/BearSSL:6105635
11:07:41.645 -> fpm close 1
11:07:41.645 -> mode : sta(30:83:98:b1:da:62)
11:07:41.645 -> add if0
11:07:41.645 -> Connecting
11:07:42.160 -> .....scandone
11:07:45.348 -> state: 0 -> 2 (b0)
11:07:45.348 -> .state: 2 -> 3 (0)
11:07:45.441 -> state: 3 -> 5 (10)
11:07:45.441 -> add 0
11:07:45.441 -> aid 6
11:07:45.441 -> cnt
11:07:45.441 ->
11:07:45.441 -> connected with HUAWEI P30 lite, channel 6
11:07:45.441 -> dhcp client start...
11:07:45.864 -> ....ip:192.168.43.88,mask:255.255.255.0,gw:192.168.43.1
11:07:47.870 -> .
11:07:47.870 -> Connected to WiFi network with IP Address: 192.168.43.88
11:07:47.870 -> [HTTP-Client][begin] url: http://192.168.56.1:3030/drink/voltron
11:07:47.870 -> [HTTP-Client][begin] host: 192.168.56.1 port: 3030 url: /drink/voltron
11:07:47.870 -> [HTTP-Client][sendRequest] type: 'POST' redirCount: 0
11:07:53.021 -> [HTTP-Client] failed connect to 192.168.56.1:3030
11:07:53.021 -> [HTTP-Client][returnError] error(-1): connection failed
11:07:53.021 -> HTTP Response code: -1
11:07:53.021 -> [HTTP-Client][end] tcp is closed

```

# Answer
> 0 votes
**TLDR**:

This is a networking problem, not a programming problem. Try changing your subnet mask to 255.255.0.0 on your router/network configuration, or make sure they're actually connected to the same router. If different routers, try to change one to a "Wireless Access Point" configuration. If you can't get them on the same network, you will have to expose your API to the Internet.

**Long version:**

You are on different subnets. Your API IP address is 192.168.56.1 and your device IP address is 192.168.43.88, but your subnet mask is 255.255.255.0. That puts these devices on separate subnets within the network.

There are a lot of complicated explanations of subnets and subnet masks on the internet. I linked one of the better ones below. Technically, you are not just on different subnets but on different networks entirely. You have a 192.x.x.x IP address, making it a Class C network. That makes your address pattern one of "network.network.network.node". Depending on your router configuration or other network hardware, you can upgrade it to a Class B network by customizing your subnet mask as 255.255.0.0 ("network.network.node.node"). Class B addresses might require a lot of customization on your end depending on your specific circumstances. By using a subnet mask of 255.255.0.0 on a Class B address, you classify the IP address parts .56.1 and .43.88 as being on the same network AND subnet. If you change it to Class B addressing without changing the subnet, the .56 will be one subnet and .43 will be a different subnet.

Sometimes this addressing is done automatically based on the installed hardware. This is especially problematic in home networks containing multiple wireless routers but connected to the same modem. Many home routers have a "Wireless Access Point" setting that removes a lot of the more complex router configuration. This *might* convince your router(s) to put you onto the same subnet. If that works, you now have your devices able to connect locally! Additional router configuration might be required to expose ports for your API to incoming requests across subnets.

If your network class is being determined by your ISP and you can't get your devices onto the same network, you have to expose your API to the Wild Wild Web :D There are many services which allow for Dynamic DNS, but I'd suggest reading through https://www.ionos.com/digitalguide/server/tools/free-dynamic-dns-providers-an-overview/ and selecting one that meets your needs. This WILL require advanced router configuration to expose ports to the internet. *Please select a Dynamic DNS services that provides DDOS protection.* Once it is exposed, your ESP8266 can hit your API as it would any public API. *Please put authentication on your API.*

References:

---
Tags: arduino-uno, esp8266, wifi, http
---


# Question
Title: ESP8266 web server not responding when running a http request function
I am trying to build something that can control a stepper motor based on weather information from openweathermap. I've set up a ESP8266 webserver to manually control motor movement with buttons and I have set up the structure to talk to openweathermap API to get the information I want (printing them to serial monitor for now for testing).

However, when I combined the 2 things break. The current code allows me to get weather perfectly but I can no longer connect to my web server running in STA mode. Something in the `getWeather()` function is messing with the web server because if I remove `getWeather()` from my loop the web server works.

Any idea what I am doing wrong here?

```
#include <SPI.h>
#include <AccelStepper.h>
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <ESP8266HTTPClient.h>  // http web access library
#include <ArduinoJson.h>        // JSON decoding library

// Define stepper motor connections and motor interface type. Motor interface type must be set to 1 when using a driver:
#define dirPin 5
#define stepPin 4
#define motorInterfaceType 1
bool motorStop;
bool motorCW;
bool motorCCW;

AccelStepper stepper = AccelStepper(motorInterfaceType, stepPin, dirPin);

//Put your SSID & Password
const char* ssid = "[ssid]";  // Enter SSID here
const char* password = "[password]";  //Enter Password here

//OpenWeatherMap API key
String apiKey= "[apikey]";

//OpenWeatherMap location
String location= "lat=37.30&lon=-121.91";
String unit= "metric";

const unsigned long postingInterval = 1000*60*60; // delay between updates, in milliseconds

WiFiClient client;

ESP8266WebServer server(80);

// Set your Static IP address
IPAddress local_IP(192, 168, 86, 248);
// Set your Gateway IP address
IPAddress gateway(192, 168, 86, 1);
IPAddress subnet(255, 255, 255, 0);
IPAddress primaryDNS(192, 168, 86, 1);

void setup() {
  Serial.begin(9600);
  delay(100);

// Configures static IP address
if (!WiFi.config(local_IP, gateway, subnet,primaryDNS)) {
  Serial.println("STA Failed to configure");
}

  stepper.setMaxSpeed(1000);

  Serial.println("Connecting to ");
  Serial.println(ssid);

  //connect to your local wi-fi network
  WiFi.begin(ssid, password);

  //check wi-fi is connected to wi-fi network
  while (WiFi.status() != WL_CONNECTED) {
  delay(1000);
  Serial.print(".");
  }
  //Print out connection info
  Serial.println("");
  Serial.println("WiFi connected..!");

  server.on("/", handle_OnConnect);
  server.on("/cw_on", handle_CW_on);
  server.on("/cw_off", handle_CW_off);
  server.on("/ccw_on", handle_CCW_on);
  server.on("/ccw_off", handle_CCW_off);
  server.on("/mstop", handle_stop);
  server.onNotFound(handle_NotFound);

  server.begin();
  Serial.println("HTTP server started");
}

void loop() {

  server.handleClient();
  if(motorStop)
  {stepper.setSpeed(0);}
  if(motorCW)
  {stepper.setSpeed(400);}
  if(motorCCW)
  {stepper.setSpeed(-400);}

  // Step the motor with a constant speed as set by setSpeed():
  stepper.runSpeed();

  getWeather();
}

void getWeather()
{
  // if there's a successful connection:
  if (client.connect("api.openweathermap.org", 80))
  {
    Serial.println("connected");
    // send the HTTP PUT request:
    client.println("GET /data/2.5/onecall?" + location + "&exclude=current,minutely,hourly" +  "&appid=" + apiKey);
    client.println("Host: api.openweathermap.org");
    client.println("Connection: close");
    client.println();

    const size_t capacity = 8*JSON_ARRAY_SIZE(1) + JSON_ARRAY_SIZE(8) + 16*JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(5) + 8*JSON_OBJECT_SIZE(6) + 8*JSON_OBJECT_SIZE(14) + 1810;
    DynamicJsonDocument doc(capacity);

    deserializeJson(doc, client);

    float lat = doc["lat"]; // 37.3
    float lon = doc["lon"]; // -121.91
    const char* timezone = doc["timezone"]; // "America/Los_Angeles"
    int timezone_offset = doc["timezone_offset"]; // -25200

    JsonArray daily = doc["daily"];

    // tomorrow's forecast (daily_1)
    JsonObject daily_1 = daily[1];
    long daily_1_dt = daily_1["dt"]; // 1596225600
    long daily_1_sunrise = daily_1["sunrise"]; // 1596201109
    long daily_1_sunset = daily_1["sunset"]; // 1596251761

    JsonObject daily_1_temp = daily_1["temp"];
    float daily_1_temp_day = daily_1_temp["day"]; // 306.61
    float daily_1_temp_min = daily_1_temp["min"]; // 288.67
    float daily_1_temp_max = daily_1_temp["max"]; // 306.61
    float daily_1_temp_night = daily_1_temp["night"]; // 288.67
    float daily_1_temp_eve = daily_1_temp["eve"]; // 295.94
    float daily_1_temp_morn = daily_1_temp["morn"]; // 293.26

    JsonObject daily_1_feels_like = daily_1["feels_like"];
    int daily_1_feels_like_day = daily_1_feels_like["day"]; // 303.31
    float daily_1_feels_like_night = daily_1_feels_like["night"]; // 287.59
    float daily_1_feels_like_eve = daily_1_feels_like["eve"]; // 293.77
    float daily_1_feels_like_morn = daily_1_feels_like["morn"]; // 292.42

    int daily_1_pressure = daily_1["pressure"]; // 1015
    int daily_1_humidity = daily_1["humidity"]; // 17
    float daily_1_dew_point = daily_1["dew_point"]; // 278.68
    float daily_1_wind_speed = daily_1["wind_speed"]; // 3.12
    int daily_1_wind_deg = daily_1["wind_deg"]; // 318

    JsonObject daily_1_weather_0 = daily_1["weather"][0];
    int daily_1_weather_0_id = daily_1_weather_0["id"]; // 800
    const char* daily_1_weather_0_main = daily_1_weather_0["main"]; // "Clear"
    const char* daily_1_weather_0_description = daily_1_weather_0["description"]; // "clear sky"
    const char* daily_1_weather_0_icon = daily_1_weather_0["icon"]; // "01d"

    int daily_1_clouds = daily_1["clouds"]; // 0
    int daily_1_pop = daily_1["pop"]; // 0
    float daily_1_uvi = daily_1["uvi"]; // 9.53

    // print out weather information
    Serial.print("Tomorrow's Forecast");
    Serial.print("Temperature: ");
    Serial.println(daily_1_feels_like_day);
    Serial.print("Weather: ");
    Serial.println(daily_1_weather_0_main);
    delay (postingInterval);
  }
  else
  {
    // if you couldn't make a connection:
    Serial.println("connection failed");
    delay (postingInterval);
  }
}

void handle_OnConnect() {
  motorStop = HIGH;
  motorCW = LOW;
  motorCCW = LOW;
  Serial.println("Motor: Stopped");
  server.send(200, "text/html", SendHTML(motorStop, motorCW, motorCCW));
}

void handle_CW_on() {
  motorStop = LOW;
  motorCW = HIGH;
  motorCCW = LOW;
  Serial.println("Motor: Running Clock-wise");
  server.send(200, "text/html", SendHTML(motorStop, motorCW, motorCCW));
}

void handle_CW_off() {
  motorStop = HIGH;
  motorCW = LOW;
  motorCCW = LOW;
  Serial.println("Motor: Stopped");
  server.send(200, "text/html", SendHTML(motorStop, motorCW, motorCCW));
}

void handle_CCW_on() {
  motorStop = LOW;
  motorCW = LOW;
  motorCCW = HIGH;
  Serial.println("Motor: Motor: Running Counter Clock-wise");
  server.send(200, "text/html", SendHTML(motorStop, motorCW, motorCCW));
}

void handle_CCW_off() {
  motorStop = HIGH;
  motorCW = LOW;
  motorCCW = LOW;
  Serial.println("Motor: Stopped");
  server.send(200, "text/html", SendHTML(motorStop, motorCW, motorCCW));
}

void handle_stop() {
  motorStop = HIGH;
  motorCW = LOW;
  motorCCW = LOW;
  Serial.println("Motor: Stopped");
  server.send(200, "text/html", SendHTML(motorStop, motorCW, motorCCW));
}

void handle_NotFound(){
  server.send(404, "text/plain", "Not found");
}

String SendHTML(uint8_t mstop,uint8_t cw, uint8_t ccw){
  String ptr = "<!DOCTYPE html> <html>\n";
  ptr +="<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0, user-scalable=no\">\n";
  ptr +="<title>LED Control</title>\n";
  ptr +="<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}\n";
  ptr +="body{margin-top: 50px;} h1 {color: #444444;margin: 50px auto 30px;} h3 {color: #444444;margin-bottom: 50px;}\n";
  ptr +=".button {display: block;width: 80px;background-color: #1abc9c;border: none;color: white;padding: 13px 30px;text-decoration: none;font-size: 25px;margin: 0px auto 35px;cursor: pointer;border-radius: 4px;}\n";
  ptr +=".button-cw {background-color: #1abc9c;}\n";
  ptr +=".button-cw:active {background-color: #16a085;}\n";
  ptr +=".button-ccw {background-color: #34495e;}\n";
  ptr +=".button-ccw:active {background-color: #2c3e50;}\n";
  ptr +=".button-mstop {background-color: #34495e;}\n";
  ptr +=".button-mstop:active {background-color: #2c3e50;}\n";
  ptr +="p {font-size: 14px;color: #888;margin-bottom: 10px;}\n";
  ptr +="</style>\n";
  ptr +="</head>\n";
  ptr +="<body>\n";
  ptr +="<h1>Weather Station</h1>\n";
  ptr +="<h3>Runs either direction continuously</h3>\n";

   if(cw)
  {ptr +="<p>Motor running Clock-wise</p><a class=\"button button-off\" href=\"/cw_off\">Stop</a>\n";}
  else
  {ptr +="<p>Motor not running Clock-wise</p><a class=\"button button-on\" href=\"/cw_on\">Run</a>\n";}

  if(ccw)
  {ptr +="<p>Motor running Counter Clock-wise</p><a class=\"button button-off\" href=\"/ccw_off\">Stop</a>\n";}
  else
  {ptr +="<p>Motor not running Counter Clock-wise</p><a class=\"button button-on\" href=\"/ccw_on\">Run</a>\n";}

  ptr +="</body>\n";
  ptr +="</html>\n";
  return ptr;
}

```

# Answer
At the end of `getWeather()` you call `delay(postingInterval);`

`postingInterval` is set to `60*60*1000` ... one hour. That means `getWeather()` won't return for one hour and nothing else in `loop()` will be processed during that time, including the web server.

You need to remove that `delay()` call and rewrite your loop to check if `postingInterval` milliseconds have passed and only call `getWeather()` if they have.
> 1 votes

---
Tags: esp8266, nodemcu, stepper-motor, esp8266webserver
---


# Question
Title: Avrdude verification error when uploading to Arduino Mega 2560
I have been getting the error

```
avrdude: verification error, first mismatch at byte 0x036c
0xb8 != 0xf8
avrdude: verification error; content mismatch
avrdude done.  Thank you.

```

When trying to upload the example blink sketch to an Arduino mega 2560.

I did some googling and found that the common recommendation to solve this is to flash the bootloader.

Which does fix the issue for the first upload after flashing, but the issue reappears after one upload. But every time I flash the bootloader I do get one successful upload following that with no errors.

The mismatch is always at 0x036c every time.

# Answer
> 1 votes
The verification is there to check two possible error situations: Transmission error while uploading or faulty flash memory. Apparently, the error can also happen for a bunch of other reasons (see the linked answer), but these two cases should still be considered. Since another Arduino works with the same cable, it's unlikely a communication error and hence, based on all we know, I am assuming your Arduino is bad.

You might be lucky that for some reason (the fault is in some piece of code that's not actually used) the program works despite the error, but it's likely that sooner or later you'll get very strange crashes or otherwise undefined behavior.

---
Tags: arduino-mega, uploading, avrdude, atmega2560
---


# Question
Title: Setup loops: never enters loop - restarting?
I uploaded the following to my UNO with WiFi:

```
#include <SPI.h>
#include <Wire.h>
#include "Adafruit_CCS811.h"

Adafruit_CCS811 ccs; // The air quality sensor

String Dataline = "";

void setup() {
  Wire.begin();

  Serial.begin(115200);
  Serial.println("SET UP");
}

void loop() {
  // wait a second between measurements.
  delay(1000);

  Dataline = "";
  Dataline = Dataline + getTime();
  Dataline = Dataline + AIRSensor();
  Dataline = Dataline + "...";
  Serial.println(Dataline);
}

String getTime() {
  String OUT = "Tim::";
  OUT += String(millis());
  return OUT;
}

String AIRSensor() {
  if (ccs.available()) {
    if (!ccs.readData()) {
      float temp = ccs.calculateTemperature();
      String CO2 = (String)ccs.geteCO2();
      return "CO2::" + CO2 +"TAQ::" + (String)temp;
    }
  } else {
    return "CO2::-999,TAQ::-999";
  }
}

```

The output is simply "SET UP" repeated:

```
SET UP
SET UP
SET UP
...

```

It never enters the loop or prints anything else out. Does this mean the UNO is resetting? How do I troubleshoot?

# Answer
> 3 votes
You can tell that something is going wrong between your `println`. Some advice in this case: eliminate the `String` entirely and replace the `println` with a series of `print`. This would let you narrow down which function is causing the problem. It also can save some memory, which is a nice bonus in embedded programming.

I suspect in this case the problem is your use of C-style casts to `String` in `AIRSensor()`. `(String)whatever` and `String(whatever)` do very different things, and the former is not something you want here, or something you should be using very often in C++ code.

The code in `loop` is running, but it is crashing and causing the hardware to reset. Since it is crashing before it reaches the first visible behavior in `loop`, it just looks like `setup` is running over and over.

---
Tags: wire-library, arduino-uno-wifi
---